52 lines
2.0 KiB
Python
52 lines
2.0 KiB
Python
import logging.config
|
||
import logging, os, sys, platform
|
||
try:
|
||
# Only available on Linux with systemd
|
||
from systemd.journal import JournalHandler # type: ignore
|
||
HAS_JOURNAL = True
|
||
except Exception:
|
||
HAS_JOURNAL = False
|
||
|
||
|
||
class MaxLevelFilter(logging.Filter):
|
||
"""Allow records up to a certain level (inclusive)."""
|
||
def __init__(self, level): super().__init__(); self.level = level
|
||
def filter(self, record): return record.levelno <= self.level
|
||
|
||
|
||
class EnsureContext(logging.Filter):
|
||
"""Always provide 'context' so the formatter never KeyErrors."""
|
||
def filter(self, record: logging.LogRecord) -> bool:
|
||
if not hasattr(record, "context"):
|
||
record.context = ""
|
||
return True
|
||
|
||
def setup_logging(level: int = logging.INFO, syslog_id: str = "energy-scrapers") -> None:
|
||
"""Use journald if available; otherwise split stdout/stderr (Windows-friendly)."""
|
||
root = logging.getLogger()
|
||
root.handlers.clear()
|
||
root.setLevel(level)
|
||
|
||
fmt = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||
|
||
if HAS_JOURNAL and platform.system() == "Linux":
|
||
# Native journald handler (preserves levels/metadata)
|
||
h = JournalHandler(SYSLOG_IDENTIFIER=syslog_id)
|
||
h.setFormatter(logging.Formatter("%(message)s")) # journald adds timestamp/level
|
||
root.addHandler(h)
|
||
else:
|
||
# Portable fallback: INFO and below -> stdout, WARNING+ -> stderr
|
||
h_out = logging.StreamHandler(sys.stdout)
|
||
h_out.setLevel(logging.DEBUG)
|
||
h_out.addFilter(MaxLevelFilter(logging.INFO))
|
||
h_out.setFormatter(fmt)
|
||
|
||
h_err = logging.StreamHandler(sys.stderr)
|
||
h_err.setLevel(logging.WARNING)
|
||
h_err.setFormatter(fmt)
|
||
|
||
root.addHandler(h_out)
|
||
root.addHandler(h_err)
|
||
|
||
# Optional: make sure Python doesn’t buffer output (useful on Windows/services)
|
||
os.environ.setdefault("PYTHONUNBUFFERED", "1") |