python 38 lines · 6 steps

Instrumenting a Flask app with Prometheus

Hook request lifecycle callbacks to record request counts and latency, then expose them on a scrape endpoint.

Explained by highlit
1from flask import Flask, request, Response
2from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
3import time
4 
5app = Flask(__name__)
6 
7REQUEST_COUNT = Counter(
8 "http_requests_total",
9 "Total number of HTTP requests",
10 ["method", "endpoint", "status"],
11)
12 
13REQUEST_LATENCY = Histogram(
14 "http_request_duration_seconds",
15 "HTTP request latency in seconds",
16 ["method", "endpoint"],
17)
18 
19 
20@app.before_request
21def start_timer():
22 request._start_time = time.perf_counter()
23 
24 
25@app.after_request
26def record_metrics(response):
27 endpoint = request.url_rule.rule if request.url_rule else request.path
28 elapsed = time.perf_counter() - getattr(request, "_start_time", time.perf_counter())
29 
30 REQUEST_LATENCY.labels(request.method, endpoint).observe(elapsed)
31 REQUEST_COUNT.labels(request.method, endpoint, response.status_code).inc()
32 
33 return response
34 
35 
36@app.route("/metrics")
37def metrics():
38 return Response(generate_latest(), mimetype=CONTENT_TYPE_LATEST)
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Prometheus client objects are declared once at module scope and mutated per request via label sets.
  2. 2Framework request hooks are a clean seam for cross-cutting concerns like timing every route.
  3. 3Using the matched url_rule instead of the raw path keeps metric label cardinality bounded.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Instrumenting a Flask app with Prometheus — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code