32 lines
1.2 KiB
Python
32 lines
1.2 KiB
Python
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())
|