pdf-quiz-generator/backend/app/logging_config.py
Daniel d0518d0737 Add comprehensive structured logging with Loki + Grafana
Backend logging:
- Centralized JSON logging config with LOG_LEVEL env var
- Request logging middleware: user, method, path, status, duration, request_id
- Fixed all 9 silent except:pass blocks to log warnings with tracebacks
- Celery workers use same structured JSON format

Infrastructure:
- Loki 3.3.2 for log storage (30-day retention)
- Promtail 3.3.2 for Docker container log shipping
- Grafana 10.3.1 with auto-provisioned Loki datasource
- Grafana on port 3002 (admin/pedshub_grafana)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 02:53:54 +02:00

52 lines
1.7 KiB
Python

"""Centralized structured JSON logging for backend and Celery workers."""
import logging
import logging.config
import sys
def setup_logging(level: str = "INFO"):
"""Configure all Python loggers to output structured JSON to stdout."""
try:
from pythonjsonlogger.json import JsonFormatter
formatter_class = "pythonjsonlogger.json.JsonFormatter"
formatter_fmt = "%(asctime)s %(name)s %(levelname)s %(message)s"
except ImportError:
# Fallback if python-json-logger not installed
formatter_class = "logging.Formatter"
formatter_fmt = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
config = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"json": {
"class": formatter_class,
"format": formatter_fmt,
"datefmt": "%Y-%m-%dT%H:%M:%S",
},
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
"formatter": "json",
},
},
"root": {
"level": level.upper(),
"handlers": ["console"],
},
"loggers": {
# Quieten noisy libraries
"uvicorn.access": {"level": "WARNING"},
"uvicorn.error": {"level": level.upper()},
"chromadb": {"level": "WARNING"},
"httpcore": {"level": "WARNING"},
"httpx": {"level": "WARNING"},
"celery": {"level": level.upper()},
"sqlalchemy.engine": {"level": "WARNING"},
},
}
logging.config.dictConfig(config)
logging.getLogger(__name__).debug("Logging configured: level=%s", level)