Files
owui-tools/app/owuitools/logging_setup.py
T
2026-09-15 15:24:03 -04:00

45 lines
1.6 KiB
Python

"""Logging that goes to a file as well as to stdout.
WHY BOTH
stdout is what `docker compose logs` reads and what Docker's own log
driver captures, so it has to stay. The file is so that every component
in this stack has ONE findable place - ./logs, bind-mounted at /logs -
rather than leaving somebody to work out which compose invocation shows
the thing they are looking for.
Falling back to stdout alone is deliberate. A container run without the
mount, or with the directory not writable, should keep working and say
why once; refusing to start because a log file could not be opened would
be the tail wagging the dog.
"""
from __future__ import annotations
import logging
import os
import sys
FORMAT = "%(asctime)s %(levelname)-7s %(name)s | %(message)s"
def configure(component: str, level: str = "INFO") -> logging.Logger:
"""stdout always; ./logs/<component>.log when the directory is there."""
handlers: list[logging.Handler] = [logging.StreamHandler(sys.stdout)]
problem = ""
log_dir = os.environ.get("OWUITOOLS_LOG_DIR", "/logs")
if log_dir:
try:
os.makedirs(log_dir, exist_ok=True)
handlers.append(logging.FileHandler(
os.path.join(log_dir, f"{component}.log"), encoding="utf-8"))
except OSError as exc:
problem = f"{log_dir} is not writable ({exc}); logging to stdout only"
logging.basicConfig(level=getattr(logging, level.upper(), logging.INFO),
format=FORMAT, handlers=handlers, force=True)
logger = logging.getLogger(component)
if problem:
logger.warning(problem)
return logger