mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-02-19 23:49:11 -05:00
This PR adds Correlation IDs to logs and request responses. ``` 2026-02-04 12:40:32,793 - [afd825081d874d6e835b5c59a6ddb371] DEBUG - media_manager.movies - get_importable_movies(): Found 5 importable movies. 2026-02-04 12:40:32,794 - [afd825081d874d6e835b5c59a6ddb371] INFO - uvicorn.access - send(): 172.19.0.1:64094 - "GET /api/v1/movies/importable HTTP/1.1" 200 2026-02-04 12:40:47,322 - [41d30b7003fd45288c6a4bb1cfba5e7a] INFO - uvicorn.access - send(): 127.0.0.1:52964 - "GET /api/v1/health HTTP/1.1" 200 2026-02-04 12:41:17,408 - [157027ea5dde472a9e620f53739ccd53] INFO - uvicorn.access - send(): 127.0.0.1:39850 - "GET /api/v1/health HTTP/1.1" 200 ```
86 lines
2.7 KiB
Python
86 lines
2.7 KiB
Python
import logging
|
|
import os
|
|
import sys
|
|
from datetime import UTC, datetime
|
|
from logging.config import dictConfig
|
|
from pathlib import Path
|
|
from typing import override
|
|
|
|
from pythonjsonlogger.json import JsonFormatter
|
|
|
|
|
|
class ISOJsonFormatter(JsonFormatter):
|
|
@override
|
|
def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str:
|
|
dt = datetime.fromtimestamp(record.created, tz=UTC)
|
|
return dt.isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
|
|
|
|
|
LOG_LEVEL = os.getenv("MEDIAMANAGER_LOG_LEVEL", "INFO").upper()
|
|
LOG_FILE = Path(os.getenv("LOG_FILE", "/app/config/media_manager.log"))
|
|
LOGGING_CONFIG = {
|
|
"version": 1,
|
|
"disable_existing_loggers": False,
|
|
"filters": {
|
|
"correlation_id": {
|
|
"()": "asgi_correlation_id.CorrelationIdFilter",
|
|
"uuid_length": 32,
|
|
"default_value": "-",
|
|
},
|
|
},
|
|
"formatters": {
|
|
"default": {
|
|
"format": "%(asctime)s - [%(correlation_id)s] %(levelname)s - %(name)s - %(funcName)s(): %(message)s"
|
|
},
|
|
"json": {
|
|
"()": ISOJsonFormatter,
|
|
"format": "%(asctime)s %(correlation_id)s %(levelname)s %(name)s %(message)s",
|
|
"rename_fields": {
|
|
"levelname": "level",
|
|
"asctime": "timestamp",
|
|
"name": "module",
|
|
},
|
|
},
|
|
},
|
|
"handlers": {
|
|
"console": {
|
|
"class": "logging.StreamHandler",
|
|
"formatter": "default",
|
|
"filters": ["correlation_id"],
|
|
"stream": sys.stdout,
|
|
},
|
|
"file": {
|
|
"class": "logging.handlers.RotatingFileHandler",
|
|
"formatter": "json",
|
|
"filters": ["correlation_id"],
|
|
"filename": str(LOG_FILE),
|
|
"maxBytes": 10485760,
|
|
"backupCount": 5,
|
|
"encoding": "utf-8",
|
|
},
|
|
},
|
|
"root": {
|
|
"level": LOG_LEVEL,
|
|
"handlers": ["console", "file"],
|
|
},
|
|
"loggers": {
|
|
"uvicorn": {"handlers": ["console", "file"], "level": "DEBUG"},
|
|
"uvicorn.access": {"handlers": ["console", "file"], "level": "DEBUG"},
|
|
"fastapi": {"handlers": ["console", "file"], "level": "DEBUG"},
|
|
},
|
|
}
|
|
|
|
|
|
def setup_logging() -> None:
|
|
dictConfig(LOGGING_CONFIG)
|
|
logging.basicConfig(
|
|
level=LOG_LEVEL,
|
|
format="%(asctime)s - %(levelname)s - %(name)s - %(funcName)s(): %(message)s",
|
|
stream=sys.stdout,
|
|
)
|
|
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
|
logging.getLogger("requests").setLevel(logging.WARNING)
|
|
logging.getLogger("transmission_rpc").setLevel(logging.WARNING)
|
|
logging.getLogger("qbittorrentapi").setLevel(logging.WARNING)
|
|
logging.getLogger("sabnzbd_api").setLevel(logging.WARNING)
|