import logging import sys class KeyValueFormatter(logging.Formatter): """Formats records as `LEVEL msg key1=val1 key2=val2`.""" def format(self, record: logging.LogRecord) -> str: base = f"{record.levelname} {record.getMessage()}" # extras land in record.__dict__ but mixed with stdlib keys; filter to known-extra keys reserved = { "name", "msg", "args", "levelname", "levelno", "pathname", "filename", "module", "exc_info", "exc_text", "stack_info", "lineno", "funcName", "created", "msecs", "relativeCreated", "thread", "threadName", "processName", "process", "message", "taskName", } extras = {k: v for k, v in record.__dict__.items() if k not in reserved} if extras: base += " " + " ".join(f"{k}={v}" for k, v in extras.items()) if record.exc_info: base += "\n" + self.formatException(record.exc_info) return base def setup_logging(level: str = "INFO") -> None: handler = logging.StreamHandler(sys.stdout) handler.setFormatter(KeyValueFormatter()) root = logging.getLogger() root.handlers.clear() root.addHandler(handler) root.setLevel(level.upper())