generated from daniil-berg/boilerplate-py
66 lines
2.3 KiB
Python
66 lines
2.3 KiB
Python
import logging as _logging
|
|
|
|
from syslogformat.helpers import check_level, py_to_sys_lvl
|
|
|
|
|
|
class SyslogFormatter(_logging.Formatter):
|
|
"""
|
|
logging.Formatter subclass for doing three things:
|
|
1) Format exception log messages into one-liners,
|
|
2) prepend a syslog oriented log level number to be recognized by systemd, and
|
|
3) append more details ([module].[function].[line]) to every message, when specified level is exceeded.
|
|
"""
|
|
def __init__(self, *args, **kwargs):
|
|
self.detail_threshold = check_level(kwargs.pop('detail_threshold', _logging.WARNING))
|
|
self.prepend_lvl_name = check_level(kwargs.pop('prepend_lvl_name', True))
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def formatException(self, exc_info) -> str:
|
|
"""Format an exception so that it prints on a single line."""
|
|
return repr(super().formatException(exc_info))
|
|
|
|
def format(self, record: _logging.LogRecord) -> str:
|
|
"""
|
|
Format to be compatible with syslog levels and replace the newlines.
|
|
The entire message format is hard-coded here, so no format needs to be specified in the usual config.
|
|
"""
|
|
record.message = record.getMessage()
|
|
|
|
# Prepend syslog level depending on record level
|
|
s = f"<{py_to_sys_lvl(record.levelno)}>"
|
|
if self.prepend_lvl_name:
|
|
s += f"{record.levelname:<8} | "
|
|
s += self.formatMessage(record)
|
|
|
|
# If record level exceeds the threshold, append additional details
|
|
if record.levelno >= self.detail_threshold:
|
|
s += f" | {record.module}.{record.funcName}.{record.lineno}"
|
|
|
|
if record.exc_info and not record.exc_text:
|
|
record.exc_text = self.formatException(record.exc_info)
|
|
if record.exc_text:
|
|
s += ' | ' + record.exc_text
|
|
if record.stack_info:
|
|
s += self.formatStack(record.stack_info)
|
|
|
|
# Reformat exception line
|
|
return s.replace("\n", "")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
log = _logging.getLogger()
|
|
hdl = _logging.StreamHandler()
|
|
fmt = SyslogFormatter()
|
|
hdl.setFormatter(fmt)
|
|
log.addHandler(hdl)
|
|
log.setLevel(_logging.NOTSET)
|
|
|
|
log.debug("foo")
|
|
log.info("bar")
|
|
log.warning("baz")
|
|
try:
|
|
raise ValueError("this is bad")
|
|
except ValueError as e:
|
|
log.exception("oh no")
|