- Keep the cumulative total requests metric (
http_requests_total). - Add a metric that represents the number of concurrent requests currently being processed (a value that can increase and decrease).
| Metric type | Behavior | When to use |
|---|---|---|
| Counter | Monotonic (only increases) | Total number of events processed (e.g., requests completed). |
| Gauge | Arbitrary instantaneous value | Point-in-time measurements that aren’t relative to previous values (e.g., memory usage). |
| Up-down counter | Increment and decrement relative to previous value | Active/in-progress counts that should rise and fall (e.g., concurrent requests). |
For tracking concurrent requests, an up-down counter is the preferred choice because its value moves up and down relative to the previous state.
- Configures a MeterProvider with a console exporter.
- Creates a cumulative
http_requests_totalcounter (incremented when responses are sent). - Creates a
concurrent_requestsup-down counter (incremented at request start, decremented after response). - Uses Flask
before_requestandafter_requesthooks to manage the concurrent counter. - Adds a slow route to let you observe concurrent requests.
before_requestruns before Flask dispatches to the route handler. We incrementconcurrent_requeststhere (withrouteandmethodattributes) to indicate a request has started.after_requestruns after the route handler returns but before the response is sent. We decrementconcurrent_requestsand incrementhttp_requests_totalhere, so the total only counts completed responses.- The slow
POST /productsroute usestime.sleep(10)so you can make multiple concurrent requests and observeconcurrent_requestsrising while requests are still in-flight.
- Fast route:
- Slow route (takes ~10 seconds to return):
- Place the total requests increment in
after_requestso you count only completed responses. - Attach attributes like
routeandmethodwith each metric call to enable dimensional filtering and per-endpoint breakdowns. For example:{"route": request.path, "method": request.method}. - Export interval controls how often metrics are pushed to the exporter. In this example the reader is configured with
export_interval_millis=5000to export every 5 seconds. - If your application can raise exceptions during request handling, consider ensuring the decrement always runs (see warning below).
If a request handler raises an exception,
after_request may not always run. To guarantee the concurrent counter is decremented in all cases, consider using Flask’s teardown_request (which runs for both successful and failed requests) or ensure exception paths also decrement the up-down counter.| Setting | Purpose | Example |
|---|---|---|
| Exporter | Sends metric data to a destination | ConsoleMetricExporter() |
| Reader | Controls export frequency | PeriodicExportingMetricReader(exporter, export_interval_millis=5000) |
| Meter name/version | Identify the instrumenting library/service | get_meter(name="shopping-app", version="0.1.2") |
| Attributes on metric calls | For dimensional metrics and filtering | {"route": request.path, "method": request.method} |
- Flask documentation: https://flask.palletsprojects.com/
- OpenTelemetry Python metrics: https://opentelemetry.io/docs/instrumentation/python/
- OpenTelemetry metrics SDK: https://github.com/open-telemetry/opentelemetry-python