diff options
author | 2021-11-14 16:55:34 +0100 | |
---|---|---|
committer | 2021-11-14 16:55:34 +0100 | |
commit | 8c2da5a0f80af4458a36cb3977d449c0cc5e039f (patch) | |
tree | e931381b6551e6e6309c21f816b9f694cf24ecd6 /bot/log.py | |
parent | Resources: add copyright notice to ryanzec_colours.json (diff) | |
parent | Merge pull request #943 from python-discord/file-log-debug (diff) |
Merge branch 'main' into color-677
Diffstat (limited to 'bot/log.py')
-rw-r--r-- | bot/log.py | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/bot/log.py b/bot/log.py new file mode 100644 index 00000000..97561be4 --- /dev/null +++ b/bot/log.py @@ -0,0 +1,99 @@ +import logging +import logging.handlers +import os +import sys +from pathlib import Path + +import coloredlogs + +from bot.constants import Client + + +def setup() -> None: + """Set up loggers.""" + # Configure the "TRACE" logging level (e.g. "log.trace(message)") + logging.TRACE = 5 + logging.addLevelName(logging.TRACE, "TRACE") + logging.Logger.trace = _monkeypatch_trace + + format_string = "%(asctime)s | %(name)s | %(levelname)s | %(message)s" + log_format = logging.Formatter(format_string) + root_logger = logging.getLogger() + + # Copied from constants file, which we can't import yet since loggers aren't instantiated + debug = os.environ.get("BOT_DEBUG", "true").lower() == "true" + + if debug: + # Set up file logging + log_file = Path("logs/sir-lancebot.log") + log_file.parent.mkdir(exist_ok=True) + + # File handler rotates logs every 5 MB + file_handler = logging.handlers.RotatingFileHandler( + log_file, maxBytes=5 * (2 ** 20), backupCount=10, encoding="utf-8", + ) + file_handler.setFormatter(log_format) + root_logger.addHandler(file_handler) + + if "COLOREDLOGS_LEVEL_STYLES" not in os.environ: + coloredlogs.DEFAULT_LEVEL_STYLES = { + **coloredlogs.DEFAULT_LEVEL_STYLES, + "trace": {"color": 246}, + "critical": {"background": "red"}, + "debug": coloredlogs.DEFAULT_LEVEL_STYLES["info"], + } + + if "COLOREDLOGS_LOG_FORMAT" not in os.environ: + coloredlogs.DEFAULT_LOG_FORMAT = format_string + + coloredlogs.install(level=logging.TRACE, stream=sys.stdout) + + root_logger.setLevel(logging.DEBUG if Client.debug else logging.INFO) + # Silence irrelevant loggers + logging.getLogger("discord").setLevel(logging.ERROR) + logging.getLogger("websockets").setLevel(logging.ERROR) + logging.getLogger("PIL").setLevel(logging.ERROR) + logging.getLogger("matplotlib").setLevel(logging.ERROR) + logging.getLogger("async_rediscache").setLevel(logging.WARNING) + + _set_trace_loggers() + + root_logger.info("Logging initialization complete") + + +def _monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None: + """ + Log 'msg % args' with severity 'TRACE'. + + To pass exception information, use the keyword argument exc_info with a true value, e.g. + logger.trace("Houston, we have an %s", "interesting problem", exc_info=1) + """ + if self.isEnabledFor(logging.TRACE): + self._log(logging.TRACE, msg, args, **kwargs) + + +def _set_trace_loggers() -> None: + """ + Set loggers to the trace level according to the value from the BOT_TRACE_LOGGERS env var. + + When the env var is a list of logger names delimited by a comma, + each of the listed loggers will be set to the trace level. + + If this list is prefixed with a "!", all of the loggers except the listed ones will be set to the trace level. + + Otherwise if the env var begins with a "*", + the root logger is set to the trace level and other contents are ignored. + """ + level_filter = Client.trace_loggers + if level_filter: + if level_filter.startswith("*"): + logging.getLogger().setLevel(logging.TRACE) + + elif level_filter.startswith("!"): + logging.getLogger().setLevel(logging.TRACE) + for logger_name in level_filter.strip("!,").split(","): + logging.getLogger(logger_name).setLevel(logging.DEBUG) + + else: + for logger_name in level_filter.strip(",").split(","): + logging.getLogger(logger_name).setLevel(logging.TRACE) |