如何使用 clipspy 将 I/O 路由到控制台和日志文件

问题描述 投票:0回答:1

我在 Ubuntu 22.0.4 LTS 上使用 clipspy v1.0.0 和 Python 3.10。

我试图通过调用我注册的函数从CLIPS规则(例如

print t 'WARN: Listen up, maggots...'
)获取命令打印到控制台,然后它将解析消息并识别它是一个警告,所以使用日志模块写一个警告级别消息到日志文件。

这是我目前所拥有的:

CLIPS 规则文件(example.clp)

(defrule welcome
(name "Tyler Durden") 
=>
(printout t "INFO: Gentlemen, welcome to Fight Club. The first rule of Fight Club is: you do not talk about Fight Club!" crlf))

Python程序(example.py)

import logging
import logging.handlers
import re

import clips

log_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.basicConfig(level=logging.INFO, format=log_format)
logger = logging.getLogger('CLIPS') 
log_level  = logging.INFO     
log_filename = 'expert'

handler = logging.handlers.TimedRotatingFileHandler(f"{log_filename}.log", when="midnight", interval=1)
handler.setLevel(log_level)
formatter = logging.Formatter(log_format)
handler.setFormatter(formatter)

# add a suffix which you want
handler.suffix = "%Y%m%d"

#need to change the extMatch variable to match the suffix for it
handler.extMatch = re.compile(r"^\d{8}$") 

# finally add handler to logger    
logger.addHandler(handler)


def my_print(msg):
    # Placeholder code, not parsing message or using logger for now ...
    print(f"CLIPS: {msg}")


try:

    env = clips.Environment()
    router = clips.LoggingRouter()
    env.add_router(router)
    env.define_function(my_print)
    env.load("example1.clp")
    env.assert_string('(name "Tyler Durden")')
    #env.reset()

    env.run()

    # while True:
    #     env.run()
except clips.CLIPSError as err:
    print(f"CLIPS error: {err}")
except KeyboardInterrupt:
    print("Stopping...")
finally:
    env.clear()

狂欢

me@yourbox$ python example.py 
2023-02-21 23:58:20,860 - INFO - INFO: Gentlemen, welcome to Fight Club. The first rule of Fight Club is: you do not talk about Fight Club!

创建了一个日志文件,但没有写入任何内容。此外,stdout 似乎只是简单地路由到 Python 的 stdout,而不是调用我的函数。

我如何修复上面的代码,以便在 CLIPS 程序中遇到

(print t)
语句时,它同时打印到控制台,并使用正确的(即指定的)日志级别写入日志。

python clips clipspy
1个回答
1
投票

clips.LoggingRouter
使用根记录器API,例如
logging.info()
。所以,请喜欢下面的例子。

import logging
import logging.handlers
import clips

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers = [
        logging.StreamHandler(),
        logging.handlers.TimedRotatingFileHandler('expert.log'),
])

env = clips.Environment()
env.add_router(clips.LoggingRouter())
...
env.run()

如果你想为处理程序指定不同的日志级别,请像下面的例子一样。

...
handler1 = logging.StreamHandler()
handler1.setLevel(logging.INFO)
handler2 = logging.handlers.TimedRotatingFileHandler('expert.log')
handler2.setLevel(logging.ERROR)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers = [handler1, handler2])

如果你想记录消息的日志级别由消息的前缀决定,定义一个

clips.LoggingRouter
的子类而不是破解
logging
模块,就像下面的例子。

...
class LoggingRouterWithLevelByPrefix(clips.LoggingRouter):
    def write(self, name, msg):
        if msg.startswith('WARN:'):
            logging.warn(msg[5:])
        elif msg.startswith('ERROR:'):
            logging.error(msg[6:])
        else:
            logging.info(msg)
...
env.add_router(LoggingRouterWithLevelByPrefix())
...

但是请记住,Clips 定义了诸如

stdout
stderr
stdwrn
等逻辑名称,
clips.LoggingRouter
使用这些名称来确定日志级别。所以你可以像下面的例子一样使用它们。

(printout t "This will be the INFO level." crlf)
(printout stdwrn "This will be the WARNING level." crlf)
(printout stderr "This will be the ERROR level." crlf)
© www.soinside.com 2019 - 2024. All rights reserved.