fix
This commit is contained in:
@@ -1,4 +1,18 @@
|
||||
"""Structured logging setup."""
|
||||
"""Structured logging setup.
|
||||
|
||||
`LOG_LEVEL` (env) controls the verbosity of:
|
||||
- The root Python logger
|
||||
- structlog-bound loggers (app.*)
|
||||
- Uvicorn's own loggers (`uvicorn`, `uvicorn.access`, `uvicorn.error`,
|
||||
`uvicorn.asgi`) — these otherwise stay at INFO regardless of LOG_LEVEL
|
||||
because uvicorn configures them itself at startup, before our lifespan
|
||||
calls setup_logging(). We forcibly re-level them here.
|
||||
- The `sqlalchemy.engine` logger (kept at WARNING unless LOG_LEVEL=DEBUG).
|
||||
|
||||
Note: `logging.basicConfig()` is a no-op once the root logger has been
|
||||
configured (which uvicorn does at import time), so it alone is NOT enough
|
||||
to honor LOG_LEVEL — we must also call `setLevel()` on each named logger.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
@@ -9,15 +23,46 @@ import structlog
|
||||
from app.config import settings
|
||||
|
||||
|
||||
# Loggers whose level must be forced to LOG_LEVEL (uvicorn pre-configures them
|
||||
# at INFO before our lifespan runs, so basicConfig cannot change them).
|
||||
_FORCED_LOGGERS = (
|
||||
"uvicorn",
|
||||
"uvicorn.access",
|
||||
"uvicorn.error",
|
||||
"uvicorn.asgi",
|
||||
"fastapi",
|
||||
)
|
||||
|
||||
|
||||
def setup_logging() -> None:
|
||||
level = getattr(logging, settings.log_level.upper(), logging.INFO)
|
||||
|
||||
# Force the root logger level (affects any logger that doesn't override).
|
||||
logging.getLogger().setLevel(level)
|
||||
|
||||
# Also call basicConfig for the formatter (idempotent if already set up).
|
||||
logging.basicConfig(
|
||||
format="%(message)s",
|
||||
stream=sys.stdout,
|
||||
level=level,
|
||||
force=True, # python 3.8+: re-init even if already configured
|
||||
)
|
||||
|
||||
# Force level on loggers that uvicorn pre-configured.
|
||||
for name in _FORCED_LOGGERS:
|
||||
lg = logging.getLogger(name)
|
||||
lg.setLevel(level)
|
||||
# Ensure uvicorn access logs propagate to the root handler.
|
||||
lg.propagate = True
|
||||
for h in lg.handlers:
|
||||
h.setLevel(level)
|
||||
|
||||
# SQLAlchemy is chatty at INFO; keep it at WARNING unless explicitly DEBUG.
|
||||
sa_level = logging.DEBUG if level <= logging.DEBUG else logging.WARNING
|
||||
logging.getLogger("sqlalchemy.engine").setLevel(sa_level)
|
||||
logging.getLogger("sqlalchemy.pool").setLevel(sa_level)
|
||||
logging.getLogger("asyncpg").setLevel(sa_level)
|
||||
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.contextvars.merge_contextvars,
|
||||
|
||||
Reference in New Issue
Block a user