|
1 | 1 | """Utility functions for logging.""" |
2 | 2 |
|
3 | 3 | import sys |
| 4 | +import time |
4 | 5 | import uuid |
5 | 6 | from collections.abc import Awaitable, Callable |
6 | 7 | from pathlib import Path |
@@ -37,6 +38,33 @@ async def add_request_context_to_log( |
37 | 38 | return await call_next(request) |
38 | 39 |
|
39 | 40 |
|
| 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 | + |
40 | 68 | async def request_response_logger( |
41 | 69 | request: Request, |
42 | 70 | call_next: Callable[[Request], Awaitable[Response]], |
|
0 commit comments