Skip to content

Commit a9f1229

Browse files
authored
Merge pull request #4 from babs/fix/uvicorn-log-propagation
fix: enable uvicorn log propagation to root structured handler
2 parents 53d56be + 45efe5b commit a9f1229

4 files changed

Lines changed: 8 additions & 5 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ app.add_middleware(fastapi_structured_logging.AccessLogMiddleware)
2222

2323
```
2424

25+
> **Important:** When using `uvicorn.run()`, pass `log_config=None` and `access_log=False` to prevent uvicorn from re-adding its default plain-text handlers over the structured logging setup. When using the uvicorn CLI, this is not needed — `setup_logging()` runs during app import, after uvicorn's logging init. Pass `--no-access-log` to let the middleware handle access logs.
26+
2527
## Configuration Options
2628

2729
The library provides extensive configuration options to customize logging and access logging behavior.

examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ app.add_middleware(fastapi_structured_logging.AccessLogMiddleware)
5555
Run the FastAPI application with OpenTelemetry instrumentation:
5656

5757
```bash
58-
uv run opentelemetry-instrument uvicorn example1:app
58+
uv run opentelemetry-instrument uvicorn example1:app --no-access-log
5959
```
6060

6161
The server will start on `http://0.0.0.0:8000`.

examples/example1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ def hello(who: str):
3131

3232

3333
if __name__ == "__main__":
34-
uvicorn.run(app, host="0.0.0.0", port=8000)
34+
uvicorn.run(app, host="0.0.0.0", port=8000, log_config=None, access_log=False)

src/fastapi_structured_logging.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,12 @@ def setup_logging(json_logs: Optional[bool] = None, log_level: str = "INFO"):
109109
root_logger = logging.getLogger()
110110
root_logger.addHandler(handler)
111111
root_logger.setLevel(log_level.upper())
112-
# Adjust Uvicorn loggers to propagate to root logger properly.
112+
# Clear uvicorn's default handlers (plain-text) and let errors propagate
113+
# to the root JSON handler. Access stays disabled — AccessLogMiddleware
114+
# handles it via structured logging instead.
113115
for log_name in ["uvicorn", "uvicorn.error"]:
114116
logging.getLogger(log_name).handlers.clear()
115-
logging.getLogger(log_name).propagate = False
117+
logging.getLogger(log_name).propagate = True
116118
logging.getLogger("uvicorn.access").handlers.clear()
117119
logging.getLogger("uvicorn.access").propagate = False
118120

@@ -177,7 +179,6 @@ def __init__(self, app: ASGIApp, config: Optional[AccessLogConfig] = None):
177179
]
178180
except ValueError:
179181
self._cache_trusted_proxy_networks = []
180-
self._cache_trusted_proxy_networks = []
181182

182183
def __is_trusted_proxy(self, ip: str) -> bool:
183184
"""Check if the given IP is in the trusted proxy CIDR ranges."""

0 commit comments

Comments
 (0)