musicmuster/app/log.py
Keith Edmunds e498457395 Add option to force DEBUG message to stderr
If the default log level for stderr is greater than DEBUG, DEBUG
message won't be shown. The DEBUG(msg) function now takes an optional
Boolean second parameter. If that is True, the DEBUG message is always
sent to stderr.
2021-06-06 10:50:40 +01:00

109 lines
2.2 KiB
Python

#!/usr/bin/python3
import logging
import logging.handlers
import sys
import traceback
from config import Config
class LevelTagFilter(logging.Filter):
"Add leveltag"
def filter(self, record):
# Extract the first character of the level name
record.leveltag = record.levelname[0]
# We never actually filter messages out, just abuse filtering to add an
# extra field to the LogRecord
return True
log = logging.getLogger(Config.LOG_NAME)
log.setLevel(logging.DEBUG)
# stderr
stderr = logging.StreamHandler()
stderr.setLevel(Config.LOG_LEVEL_STDERR)
# syslog
syslog = logging.handlers.SysLogHandler(address='/dev/log')
syslog.setLevel(Config.LOG_LEVEL_SYSLOG)
# Filter
filter = LevelTagFilter()
syslog.addFilter(filter)
stderr.addFilter(filter)
# create formatter and add it to the handlers
stderr_fmt = logging.Formatter('[%(asctime)s] %(leveltag)s: %(message)s',
datefmt='%H:%M:%S')
syslog_fmt = logging.Formatter('[%(name)s] %(leveltag)s: %(message)s')
stderr.setFormatter(stderr_fmt)
syslog.setFormatter(syslog_fmt)
# add the handlers to the log
log.addHandler(stderr)
log.addHandler(syslog)
def log_uncaught_exceptions(ex_cls, ex, tb):
print("\033[1;31;47m")
logging.critical(''.join(traceback.format_tb(tb)))
print("\033[1;37;40m")
logging.critical('{0}: {1}'.format(ex_cls, ex))
sys.excepthook = log_uncaught_exceptions
def DEBUG(msg, force_stderr=False):
"""
Outupt a log message at level DEBUG. If force_stderr is True,
output this message to stderr regardless of default stderr level
setting.
"""
if force_stderr:
old_level = stderr.level
stderr.setLevel(logging.DEBUG)
log.debug(msg)
stderr.setLevel(old_level)
else:
log.debug(msg)
def EXCEPTION(msg):
log.exception(msg, exc_info=True, stack_info=True)
def ERROR(msg):
log.error(msg)
def INFO(msg):
log.info(msg)
if __name__ == "__main__":
DEBUG("hi debug")
ERROR("hi error")
INFO("hi info")
EXCEPTION("hi exception")
def f():
return g()
def g():
return h()
def h():
return i()
def i():
1 / 0
f()