I am using clipspy v1.0.0 and Python 3.10 on Ubuntu 22.0.4 LTS.
I am trying to get commands from CLIPS rules (e.g. print t 'WARN: Listen up, maggots...'
) to print to the console by calling my registered function, which will then parse the message and recognise that it is a warning, so use the logging module to write a warning level message to the log file.
This is what I have so far:
CLIPS rule file (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 program (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()
Bash
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!
A log file is created, but nothing is written to it. Also, it seems stdout is being simply routed to Pythons stdout, instead of calling my function.
How do I fix the code above, so that when a (print t)
statement is encountered in a CLIPS program, it, it simultaneously prints to console, and writes to log using the correct (i.e. specified) log level.
The
clips.LoggingRouter
uses the root logger API such aslogging.info()
. So, do like the following example.If you want to specify different log levels for handlers, do like the following example.
If you want to log a message with the log level determined by the prefix of the message, define a subclass of the
clips.LoggingRouter
instead of hacking thelogging
module, like the following example.But keep in mind that Clips defines logical names such as
stdout
,stderr
,stdwrn
, whichclips.LoggingRouter
uses to determine the log level. So you can use them like the following example.