ModPilot / observability /logging.py
ThejasRao's picture
Deploy ModPilot Investigation Engine
7302343
Raw
History Blame Contribute Delete
1.42 kB
"""Structured logging — structlog with JSON in prod, console in dev.
Spec: docs/Specs.md §15, docs/14-Engineering.md §3.1
Every log carries `correlation_id` when present in context.
"""
import logging
import sys
from typing import Any
import structlog
def configure_logging(*, level: str = "INFO", env: str = "development") -> None:
"""Idempotent. Safe to call from app startup and from tests."""
logging.basicConfig(
format="%(message)s",
stream=sys.stdout,
level=getattr(logging, level),
)
shared_processors: list[Any] = [
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="iso", utc=True),
structlog.processors.StackInfoRenderer(),
structlog.dev.set_exc_info,
]
if env == "development":
renderer: Any = structlog.dev.ConsoleRenderer(colors=True)
else:
renderer = structlog.processors.JSONRenderer()
structlog.configure(
processors=[*shared_processors, renderer],
wrapper_class=structlog.make_filtering_bound_logger(getattr(logging, level)),
context_class=dict,
logger_factory=structlog.PrintLoggerFactory(),
cache_logger_on_first_use=True,
)
def get_logger(name: str | None = None) -> structlog.stdlib.BoundLogger:
return structlog.get_logger(name) # type: ignore[no-any-return]