1
|
import time
|
2
|
|
3
|
from prometheus_client import Counter, Gauge, Histogram
|
4
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
5
|
from starlette.requests import Request
|
6
|
from starlette.responses import Response
|
7
|
|
8
|
REQUESTS = Counter("starlette_requests_total", "Total count of requests by method and path.", ["method", "path"])
|
9
|
RESPONSES = Counter(
|
10
|
"scholexplorerAPI_responses_total",
|
11
|
"Total count of responses by method, path and status codes.",
|
12
|
["method", "path", "status_code"],
|
13
|
)
|
14
|
REQUESTS_PROCESSING_TIME = Histogram(
|
15
|
"scholexplorerAPI_requests_processing_time_seconds",
|
16
|
"Histogram of requests processing time by path (in seconds)",
|
17
|
["method", "path"],
|
18
|
)
|
19
|
EXCEPTIONS = Counter(
|
20
|
"scholexplorerAPI_exceptions_total",
|
21
|
"Histogram of exceptions raised by path and exception type",
|
22
|
["method", "path", "exception_type"],
|
23
|
)
|
24
|
REQUESTS_IN_PROGRESS = Gauge(
|
25
|
"scholexplorerAPI_requests_in_progress",
|
26
|
"Gauge of requests by method and path currently being processed",
|
27
|
["method", "path"],
|
28
|
)
|
29
|
|
30
|
|
31
|
class PrometheusMiddleware(BaseHTTPMiddleware):
|
32
|
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
|
33
|
method = request.method
|
34
|
path = request.url.path
|
35
|
|
36
|
REQUESTS_IN_PROGRESS.labels(method=method, path=path).inc()
|
37
|
REQUESTS.labels(method=method, path=path).inc()
|
38
|
try:
|
39
|
before_time = time.time()
|
40
|
response = await call_next(request)
|
41
|
after_time = time.time()
|
42
|
except Exception as e:
|
43
|
EXCEPTIONS.labels(method=method, path=path, exception_type=type(e).__name__).inc()
|
44
|
raise e from None
|
45
|
else:
|
46
|
REQUESTS_PROCESSING_TIME.labels(method=method, path=path).observe(after_time - before_time)
|
47
|
RESPONSES.labels(method=method, path=path, status_code=response.status_code).inc()
|
48
|
finally:
|
49
|
REQUESTS_IN_PROGRESS.labels(method=method, path=path).dec()
|
50
|
|
51
|
return response
|