Skip to content

Commit f55b798

Browse files
committed
Add middleware for logging response times
1 parent 175f402 commit f55b798

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

src/core/logging.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Utility functions for logging."""
22

33
import sys
4+
import time
45
import uuid
56
from collections.abc import Awaitable, Callable
67
from pathlib import Path
@@ -37,6 +38,33 @@ async def add_request_context_to_log(
3738
return await call_next(request)
3839

3940

41+
async def log_request_duration(
42+
request: Request,
43+
call_next: Callable[[Request], Awaitable[Response]],
44+
) -> Response:
45+
"""Log the process and wallclock time for each call.
46+
47+
Reported times cannot be attributed solely to processing the request.
48+
As multiple requests can be handled concurrently in the same process,
49+
process time may be spent on other requests as well. The same goes for
50+
wallclock time, which is additionally influenced by e.g., context switches.
51+
"""
52+
start_mono_ns = time.monotonic_ns()
53+
start_process_ns = time.process_time_ns()
54+
response: Response = await call_next(request)
55+
56+
duration_mono_ns = time.monotonic_ns() - start_mono_ns
57+
duration_process_ns = time.process_time_ns() - start_process_ns
58+
logger.info(
59+
"Request took {mono_ms} ms wallclock time (process time {process_ms} ms)",
60+
mono_ms=int(duration_mono_ns / 1_000_000),
61+
process_ms=int(duration_process_ns / 1_000_000),
62+
wallclock_time_ns=duration_mono_ns,
63+
process_time_ns=duration_process_ns,
64+
)
65+
return response
66+
67+
4068
async def request_response_logger(
4169
request: Request,
4270
call_next: Callable[[Request], Awaitable[Response]],

src/main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010

1111
from config import load_configuration
1212
from core.errors import ProblemDetailError, problem_detail_exception_handler
13-
from core.logging import add_request_context_to_log, request_response_logger, setup_log_sinks
13+
from core.logging import (
14+
add_request_context_to_log,
15+
log_request_duration,
16+
request_response_logger,
17+
setup_log_sinks,
18+
)
1419
from database.setup import close_databases
1520
from routers.mldcat_ap.dataset import router as mldcat_ap_router
1621
from routers.openml.datasets import router as datasets_router
@@ -72,6 +77,7 @@ def create_api(configuration_file: Path | None = None) -> FastAPI:
7277
# Order matters! Each added middleware wraps the previous, creating a stack.
7378
# See also: https://fastapi.tiangolo.com/tutorial/middleware/#multiple-middleware-execution-order
7479
app.middleware("http")(request_response_logger)
80+
app.middleware("http")(log_request_duration)
7581
app.middleware("http")(add_request_context_to_log)
7682

7783
app.add_exception_handler(ProblemDetailError, problem_detail_exception_handler) # type: ignore[arg-type]

0 commit comments

Comments
 (0)