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
```
This commit is contained in:
Maximilian Dorninger
2026-02-04 13:55:05 +01:00
committed by GitHub
parent 24fcba6bee
commit c45c9e5873
4 changed files with 29 additions and 2 deletions

View File

@@ -21,13 +21,20 @@ LOG_FILE = Path(os.getenv("LOG_FILE", "/app/config/media_manager.log"))
LOGGING_CONFIG = { LOGGING_CONFIG = {
"version": 1, "version": 1,
"disable_existing_loggers": False, "disable_existing_loggers": False,
"filters": {
"correlation_id": {
"()": "asgi_correlation_id.CorrelationIdFilter",
"uuid_length": 32,
"default_value": "-",
},
},
"formatters": { "formatters": {
"default": { "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": { "json": {
"()": ISOJsonFormatter, "()": ISOJsonFormatter,
"format": "%(asctime)s %(levelname)s %(name)s %(message)s", "format": "%(asctime)s %(correlation_id)s %(levelname)s %(name)s %(message)s",
"rename_fields": { "rename_fields": {
"levelname": "level", "levelname": "level",
"asctime": "timestamp", "asctime": "timestamp",
@@ -39,11 +46,13 @@ LOGGING_CONFIG = {
"console": { "console": {
"class": "logging.StreamHandler", "class": "logging.StreamHandler",
"formatter": "default", "formatter": "default",
"filters": ["correlation_id"],
"stream": sys.stdout, "stream": sys.stdout,
}, },
"file": { "file": {
"class": "logging.handlers.RotatingFileHandler", "class": "logging.handlers.RotatingFileHandler",
"formatter": "json", "formatter": "json",
"filters": ["correlation_id"],
"filename": str(LOG_FILE), "filename": str(LOG_FILE),
"maxBytes": 10485760, "maxBytes": 10485760,
"backupCount": 5, "backupCount": 5,

View File

@@ -2,6 +2,7 @@ import logging
import os import os
import uvicorn import uvicorn
from asgi_correlation_id import CorrelationIdMiddleware
from fastapi import APIRouter, FastAPI, Request, Response from fastapi import APIRouter, FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
@@ -71,6 +72,7 @@ app.add_middleware(
allow_credentials=True, allow_credentials=True,
allow_methods=["GET", "PUT", "POST", "DELETE", "PATCH", "HEAD", "OPTIONS"], allow_methods=["GET", "PUT", "POST", "DELETE", "PATCH", "HEAD", "OPTIONS"],
) )
app.add_middleware(CorrelationIdMiddleware, header_name="X-Correlation-ID")
api_app = APIRouter(prefix="/api/v1") api_app = APIRouter(prefix="/api/v1")

View File

@@ -34,6 +34,7 @@ dependencies = [
"transmission-rpc>=7.0.11", "transmission-rpc>=7.0.11",
"libtorrent>=2.0.11", "libtorrent>=2.0.11",
"pathvalidate>=3.3.1", "pathvalidate>=3.3.1",
"asgi-correlation-id>=4.3.4",
] ]
[dependency-groups] [dependency-groups]

15
uv.lock generated
View File

@@ -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" }, { 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]] [[package]]
name = "attrs" name = "attrs"
version = "25.4.0" version = "25.4.0"
@@ -854,6 +867,7 @@ source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "alembic" }, { name = "alembic" },
{ name = "apscheduler" }, { name = "apscheduler" },
{ name = "asgi-correlation-id" },
{ name = "bencoder" }, { name = "bencoder" },
{ name = "cachetools" }, { name = "cachetools" },
{ name = "fastapi", extra = ["standard"] }, { name = "fastapi", extra = ["standard"] },
@@ -894,6 +908,7 @@ dev = [
requires-dist = [ requires-dist = [
{ name = "alembic", specifier = ">=1.16.1" }, { name = "alembic", specifier = ">=1.16.1" },
{ name = "apscheduler", specifier = ">=3.11.0" }, { name = "apscheduler", specifier = ">=3.11.0" },
{ name = "asgi-correlation-id", specifier = ">=4.3.4" },
{ name = "bencoder", specifier = ">=0.2.0" }, { name = "bencoder", specifier = ">=0.2.0" },
{ name = "cachetools", specifier = ">=6.0.0" }, { name = "cachetools", specifier = ">=6.0.0" },
{ name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" },