From c45c9e58738c195a26571d3e757336919bda2b13 Mon Sep 17 00:00:00 2001 From: Maximilian Dorninger <97409287+maxdorninger@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:55:05 +0100 Subject: [PATCH] add correlation id to logging (#398) 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 ``` --- media_manager/logging.py | 13 +++++++++++-- media_manager/main.py | 2 ++ pyproject.toml | 1 + uv.lock | 15 +++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/media_manager/logging.py b/media_manager/logging.py index af36d8a..d222966 100644 --- a/media_manager/logging.py +++ b/media_manager/logging.py @@ -21,13 +21,20 @@ 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 - %(levelname)s - %(name)s - %(funcName)s(): %(message)s" + "format": "%(asctime)s - [%(correlation_id)s] %(levelname)s - %(name)s - %(funcName)s(): %(message)s" }, "json": { "()": ISOJsonFormatter, - "format": "%(asctime)s %(levelname)s %(name)s %(message)s", + "format": "%(asctime)s %(correlation_id)s %(levelname)s %(name)s %(message)s", "rename_fields": { "levelname": "level", "asctime": "timestamp", @@ -39,11 +46,13 @@ LOGGING_CONFIG = { "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, diff --git a/media_manager/main.py b/media_manager/main.py index 772f8c2..ceed7c3 100644 --- a/media_manager/main.py +++ b/media_manager/main.py @@ -2,6 +2,7 @@ import logging import os import uvicorn +from asgi_correlation_id import CorrelationIdMiddleware from fastapi import APIRouter, FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles @@ -71,6 +72,7 @@ app.add_middleware( allow_credentials=True, allow_methods=["GET", "PUT", "POST", "DELETE", "PATCH", "HEAD", "OPTIONS"], ) +app.add_middleware(CorrelationIdMiddleware, header_name="X-Correlation-ID") api_app = APIRouter(prefix="/api/v1") diff --git a/pyproject.toml b/pyproject.toml index e7319ba..a6d1efd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ "transmission-rpc>=7.0.11", "libtorrent>=2.0.11", "pathvalidate>=3.3.1", + "asgi-correlation-id>=4.3.4", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index 27bd392..7d7c595 100644 --- a/uv.lock +++ b/uv.lock @@ -105,6 +105,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, ] +[[package]] +name = "asgi-correlation-id" +version = "4.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075, upload-time = "2024-10-17T11:44:30.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262, upload-time = "2024-10-17T11:44:28.739Z" }, +] + [[package]] name = "attrs" version = "25.4.0" @@ -854,6 +867,7 @@ source = { virtual = "." } dependencies = [ { name = "alembic" }, { name = "apscheduler" }, + { name = "asgi-correlation-id" }, { name = "bencoder" }, { name = "cachetools" }, { name = "fastapi", extra = ["standard"] }, @@ -894,6 +908,7 @@ dev = [ requires-dist = [ { name = "alembic", specifier = ">=1.16.1" }, { name = "apscheduler", specifier = ">=3.11.0" }, + { name = "asgi-correlation-id", specifier = ">=4.3.4" }, { name = "bencoder", specifier = ">=0.2.0" }, { name = "cachetools", specifier = ">=6.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" },