我在 Ubuntu 22.0.4 LTS 上使用 clipspy v1.0.0 和 Python 3.10。
我试图通过调用我注册的函数从CLIPS规则(例如
print t 'WARN: Listen up, maggots...'
)获取命令打印到控制台,然后它将解析消息并识别它是一个警告,所以使用日志模块写一个警告级别消息到日志文件。
这是我目前所拥有的:
(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))
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)
语句时,它同时打印到控制台,并使用正确的(即指定的)日志级别写入日志。
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)