From 3afcfd585695743bd5bd2670696f424fac5313eb Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Mon, 27 Jan 2025 12:11:42 +0000 Subject: [PATCH] Move to YAML-configured logging --- app/log.py | 52 +++++++++++++++++++++---------------------- app/logging.yaml | 46 ++++++++++++++++++++++++++++++++++++++ app/logging_tester.py | 27 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 27 deletions(-) mode change 100644 => 100755 app/log.py create mode 100644 app/logging.yaml create mode 100755 app/logging_tester.py diff --git a/app/log.py b/app/log.py old mode 100644 new mode 100755 index eb49b79..591294b --- a/app/log.py +++ b/app/log.py @@ -1,56 +1,54 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # Standard library imports import logging +import logging.config import logging.handlers import os import sys from traceback import print_exception +import yaml # PyQt imports # Third party imports -import colorlog import stackprinter # type: ignore # App imports from config import Config +class FunctionFilter(logging.Filter): + """Filter to allow category-based logging to stderr.""" + + def __init__(self, functions: set[str]): + super().__init__() + self.functions = functions + + def filter(self, record: logging.LogRecord) -> bool: + return ( + getattr(record, "funcName", None) in self.functions + and getattr(record, "levelname", None) == "DEBUG" + ) + + class LevelTagFilter(logging.Filter): """Add leveltag""" def filter(self, record: logging.LogRecord) -> bool: # 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 + # We never actually filter messages out, just add an extra field + # to the LogRecord return True +# Load YAML logging configuration +with open("app/logging.yaml", "r") as f: + config = yaml.safe_load(f) + logging.config.dictConfig(config) + +# Get logger log = logging.getLogger(Config.LOG_NAME) -log.setLevel(logging.DEBUG) -local_filter = LevelTagFilter() - -# stderr -stderr = colorlog.StreamHandler() -stderr.setLevel(Config.LOG_LEVEL_STDERR) -stderr.addFilter(local_filter) -stderr_fmt = colorlog.ColoredFormatter( - "%(log_color)s[%(asctime)s] %(filename)s:%(lineno)s %(message)s", datefmt="%H:%M:%S" -) -stderr.setFormatter(stderr_fmt) -log.addHandler(stderr) - -# syslog -syslog = logging.handlers.SysLogHandler(address="/dev/log") -syslog.setLevel(Config.LOG_LEVEL_SYSLOG) -syslog.addFilter(local_filter) -syslog_fmt = logging.Formatter( - "[%(name)s] %(filename)s:%(lineno)s %(leveltag)s: %(message)s" -) -syslog.setFormatter(syslog_fmt) -log.addHandler(syslog) def log_uncaught_exceptions(type_, value, traceback): diff --git a/app/logging.yaml b/app/logging.yaml new file mode 100644 index 0000000..99a7562 --- /dev/null +++ b/app/logging.yaml @@ -0,0 +1,46 @@ +version: 1 +disable_existing_loggers: True + +formatters: + colored: + (): colorlog.ColoredFormatter + format: "%(log_color)s[%(asctime)s] %(filename)s:%(lineno)s %(message)s" + datefmt: "%H:%M:%S" + syslog: + format: "[%(name)s] %(filename)s:%(lineno)s %(leveltag)s: %(message)s" + +filters: + leveltag: + (): newlogger.LevelTagFilter + category_filter: + (): newlogger.FunctionFilter + functions: !!set + fb: null + +handlers: + stderr: + class: colorlog.StreamHandler + level: INFO + formatter: colored + filters: [leveltag] + stream: ext://sys.stderr + + syslog: + class: logging.handlers.SysLogHandler + level: DEBUG + formatter: syslog + filters: [leveltag] + address: "/dev/log" + + debug_stderr: + class: colorlog.StreamHandler + level: DEBUG + formatter: colored + filters: [leveltag, category_filter] + stream: ext://sys.stderr + +loggers: + musicmuster: + level: DEBUG + handlers: [stderr, syslog, debug_stderr] + propagate: false diff --git a/app/logging_tester.py b/app/logging_tester.py new file mode 100755 index 0000000..5d5d505 --- /dev/null +++ b/app/logging_tester.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +from newlogger import log +# Testing +def fa(): + log.debug("fa Debug message") + log.info("fa Info message") + log.warning("fa Warning message") + log.error("fa Error message") + log.critical("fa Critical message") + print() + + +def fb(): + log.debug("fb Debug message") + log.info("fb Info message") + log.warning("fb Warning message") + log.error("fb Error message") + log.critical("fb Critical message") + print() + + +def testing(): + fa() + fb() + + +testing()