Skip to content

Commit c591a6f

Browse files
šŸ› Process canonical endpoint in fastapi case when collecting prometheus metrics (#7704)
1 parent 3c12ac2 commit c591a6f

File tree

3 files changed

+23
-17
lines changed

3 files changed

+23
-17
lines changed

ā€Žpackages/service-library/src/servicelib/aiohttp/monitoring.pyā€Ž

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import asyncio
44
import logging
5-
import time
65
from collections.abc import Awaitable, Callable
6+
from time import perf_counter
77
from typing import Final
88

99
from aiohttp import web
@@ -67,7 +67,7 @@ async def middleware_handler(request: web.Request, handler: Handler):
6767
canonical_endpoint = request.path
6868
if request.match_info.route.resource:
6969
canonical_endpoint = request.match_info.route.resource.canonical
70-
start_time = time.time()
70+
start_time = perf_counter()
7171
try:
7272
if enter_middleware_cb:
7373
with log_catch(logger=log, reraise=False):
@@ -111,14 +111,15 @@ async def middleware_handler(request: web.Request, handler: Handler):
111111
raise resp from exc
112112

113113
finally:
114-
resp_time_secs: float = time.time() - start_time
114+
response_latency_seconds = perf_counter() - start_time
115115

116116
record_response_metrics(
117117
metrics=metrics,
118118
method=request.method,
119119
endpoint=canonical_endpoint,
120120
user_agent=user_agent,
121121
http_status=resp.status,
122+
response_latency_seconds=response_latency_seconds,
122123
)
123124

124125
if exit_middleware_cb:
@@ -133,7 +134,7 @@ async def middleware_handler(request: web.Request, handler: Handler):
133134
request.remote,
134135
request.method,
135136
request.path,
136-
resp_time_secs,
137+
response_latency_seconds,
137138
resp.status,
138139
exc_info=log_exception,
139140
stack_info=True,

ā€Žpackages/service-library/src/servicelib/fastapi/monitoring.pyā€Ž

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import logging
55
from collections.abc import AsyncIterator
6+
from time import perf_counter
67
from typing import Final
78

89
from fastapi import FastAPI, Request, Response, status
@@ -39,10 +40,12 @@ async def dispatch(
3940
self, request: Request, call_next: RequestResponseEndpoint
4041
) -> Response:
4142
canonical_endpoint = request.url.path
43+
4244
user_agent = request.headers.get(
4345
X_SIMCORE_USER_AGENT, UNDEFINED_DEFAULT_SIMCORE_USER_AGENT_VALUE
4446
)
4547

48+
start_time = perf_counter()
4649
try:
4750
with record_request_metrics(
4851
metrics=self.metrics,
@@ -52,18 +55,26 @@ async def dispatch(
5255
):
5356
response = await call_next(request)
5457
status_code = response.status_code
58+
59+
# path_params are not available before calling call_next
60+
# https://github.com/encode/starlette/issues/685#issuecomment-550240999
61+
for k, v in request.path_params.items():
62+
key = "{" + k + "}"
63+
canonical_endpoint = canonical_endpoint.replace(f"/{v}", f"/{key}")
5564
except Exception: # pylint: disable=broad-except
5665
# NOTE: The prometheus metrics middleware should be "outside" exception handling
5766
# middleware. See https://fastapi.tiangolo.com/advanced/middleware/#adding-asgi-middlewares
5867
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
5968
raise
6069
finally:
70+
reponse_latency_seconds = perf_counter() - start_time
6171
record_response_metrics(
6272
metrics=self.metrics,
6373
method=request.method,
6474
endpoint=canonical_endpoint,
6575
user_agent=user_agent,
6676
http_status=status_code,
77+
response_latency_seconds=reponse_latency_seconds,
6778
)
6879

6980
return response

ā€Žpackages/service-library/src/servicelib/prometheus_metrics.pyā€Ž

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from collections.abc import Iterator
22
from contextlib import contextmanager
33
from dataclasses import dataclass
4-
from time import perf_counter
54

65
from opentelemetry import trace
76
from prometheus_client import (
@@ -132,20 +131,8 @@ def record_request_metrics(
132131
with metrics.in_flight_requests.labels(
133132
method, endpoint, user_agent
134133
).track_inprogress():
135-
136-
start = perf_counter()
137-
138134
yield
139135

140-
amount = perf_counter() - start
141-
exemplar = _get_exemplar()
142-
metrics.response_latency_with_labels.labels(
143-
method, endpoint, user_agent
144-
).observe(amount=amount, exemplar=exemplar)
145-
metrics.response_latency_detailed_buckets.observe(
146-
amount=amount, exemplar=exemplar
147-
)
148-
149136

150137
def record_response_metrics(
151138
*,
@@ -154,8 +141,15 @@ def record_response_metrics(
154141
endpoint: str,
155142
user_agent: str,
156143
http_status: int,
144+
response_latency_seconds: float,
157145
) -> None:
158146
exemplar = _get_exemplar()
159147
metrics.request_count.labels(method, endpoint, http_status, user_agent).inc(
160148
exemplar=exemplar
161149
)
150+
metrics.response_latency_with_labels.labels(method, endpoint, user_agent).observe(
151+
amount=response_latency_seconds, exemplar=exemplar
152+
)
153+
metrics.response_latency_detailed_buckets.observe(
154+
amount=response_latency_seconds, exemplar=exemplar
155+
)

0 commit comments

Comments
Ā (0)