Skip to content

Commit 48c34df

Browse files
committed
refactor: type request/provider logging payloads and monitoring helpers
1 parent bf36a0b commit 48c34df

2 files changed

Lines changed: 49 additions & 15 deletions

File tree

app/logging.py

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import uuid
99
from collections.abc import Iterable
1010
from datetime import UTC, datetime
11-
from typing import Any
11+
from typing import Any, TypedDict
1212

1313
from flask import g, has_request_context, request
1414
from werkzeug.exceptions import HTTPException
@@ -43,6 +43,32 @@
4343
}
4444

4545

46+
class RequestLogPayload(TypedDict, total=False):
47+
event: str
48+
route: str
49+
method: str
50+
status: int
51+
duration_ms: float
52+
request_id: str
53+
path: str
54+
source: str
55+
stale: bool
56+
error: str
57+
client_ip: str
58+
59+
60+
class ProviderLogPayload(TypedDict, total=False):
61+
event: str
62+
provider: str
63+
base: str
64+
status: str
65+
duration_ms: float
66+
request_id: str | None
67+
source: str
68+
stale: bool
69+
error: str
70+
71+
4672
class JSONLogFormatter(logging.Formatter):
4773
"""Format LogRecord instances into structured JSON strings."""
4874

@@ -170,25 +196,27 @@ def _build_request_log_extra(
170196
request_id: str | None,
171197
duration_ms: float | None,
172198
error: str | None,
173-
) -> dict[str, Any]:
199+
) -> RequestLogPayload:
174200
route = request.url_rule.rule if request.url_rule else request.path
175-
payload: dict[str, Any] = {
201+
payload: RequestLogPayload = {
176202
"event": event,
177203
"route": route,
178204
"method": request.method,
179205
"status": status,
180-
"duration_ms": round(duration_ms, 3) if duration_ms is not None else None,
181-
"request_id": request_id,
182206
"path": request.path,
183207
"source": "api",
184208
"stale": False,
185209
}
210+
if duration_ms is not None:
211+
payload["duration_ms"] = round(duration_ms, 3)
212+
if request_id:
213+
payload["request_id"] = request_id
186214
if error:
187215
payload["error"] = error
188216
if request.remote_addr:
189217
payload["client_ip"] = request.remote_addr
190218

191-
return {key: value for key, value in payload.items() if value is not None}
219+
return payload
192220

193221

194222
def _extract_extras(record_dict: dict[str, Any]) -> dict[str, Any]:
@@ -243,20 +271,21 @@ def provider_log_extra(
243271
duration_ms: float | None,
244272
stale: bool,
245273
error: str | None = None,
246-
) -> dict[str, Any]:
247-
payload: dict[str, Any] = {
274+
) -> ProviderLogPayload:
275+
payload: ProviderLogPayload = {
248276
"event": event,
249277
"provider": provider,
250278
"base": base,
251279
"status": status,
252-
"duration_ms": round(duration_ms, 3) if duration_ms is not None else None,
253-
"request_id": _current_request_id(),
254280
"source": provider,
255281
"stale": stale,
256282
}
283+
if duration_ms is not None:
284+
payload["duration_ms"] = round(duration_ms, 3)
285+
payload["request_id"] = _current_request_id()
257286
if error:
258287
payload["error"] = error
259-
return {key: value for key, value in payload.items() if value is not None}
288+
return payload
260289

261290

262291
def _current_request_id() -> str | None:

app/monitoring.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@
66
from collections.abc import Callable, Iterator, Mapping, MutableMapping
77
from contextlib import contextmanager
88
from time import perf_counter
9-
from typing import Any, cast
9+
from typing import Any, Protocol, cast
1010

1111
from flask import Flask, current_app, g
1212

13+
14+
class MetadataFactory(Protocol):
15+
def __call__(self, *args: Any, **kwargs: Any) -> Mapping[str, Any] | None: ...
16+
17+
1318
LOG_EVENT_NAME = "performance.timing"
1419
CONFIG_ENABLED_KEY = "TIMING_LOGS_ENABLED"
1520
CONFIG_THRESHOLD_KEY = "TIMING_MIN_DURATION_MS"
1621

1722

18-
def _is_enabled(app) -> bool:
23+
def _is_enabled(app: Flask) -> bool:
1924
value = app.config.get(CONFIG_ENABLED_KEY, False)
2025
if isinstance(value, bool):
2126
return value
2227
return str(value).strip().lower() in {"1", "true", "yes", "on"}
2328

2429

25-
def _threshold_ms(app) -> float | None:
30+
def _threshold_ms(app: Flask) -> float | None:
2631
value = app.config.get(CONFIG_THRESHOLD_KEY)
2732
if value is None:
2833
return None
@@ -112,7 +117,7 @@ def timed_operation(
112117
def timed(
113118
event: str,
114119
*,
115-
metadata_factory: Callable[..., Mapping[str, Any] | None] | None = None,
120+
metadata_factory: MetadataFactory | None = None,
116121
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
117122
"""Decorator variant of ``timed_operation`` for function instrumentation."""
118123

0 commit comments

Comments
 (0)