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