Skip to main content
In this lesson we add a new metric to track memory usage for a Flask API (“shopping-app”) using OpenTelemetry for Python. We choose an observable (polled) gauge implemented with psutil and export metrics to the console via a PeriodicExportingMetricReader. This demonstrates setting up a MeterProvider, registering a polled gauge callback, and using synchronous counters to instrument requests. Why choose an observable gauge?
  • Counters only increase; they are not suitable for values that go up and down.
  • Up-down counters are for values your code explicitly increments/decrements (e.g., concurrent requests).
  • Memory usage fluctuates and is independent of prior values, so a gauge is the correct metric type.
  • An observable (async) gauge lets the SDK poll the current memory values periodically, so you do not need to manually update the metric inside your application code.
Observable gauges are polled by the metrics SDK (via the metric reader). You must provide a callback function that returns the current observations; the SDK will call that callback periodically according to the metric reader’s export interval.

Example: Flask app with an observable gauge (polled memory)

This self-contained example shows:
  • Meter/provider setup with a ConsoleMetricExporter and 5s periodic exporting.
  • Synchronous metrics: request counters and an up-down counter for concurrent requests.
  • An observable gauge that reports RSS and VMS memory values for the running process.
Install psutil (used to read the process memory):

Example console-exported metric snapshot

The ConsoleMetricExporter prints resource and scope metrics as JSON-like structures. With the periodic reader configured to 5000 ms, the observable gauge will be polled every 5 seconds and you will see observations for rss and vms within the exported metrics.

Quick reference: metric types and when to use them

Metric TypeUse CaseWhen to use
CounterMonotonic counts of eventshttp_requests_total (increment on each request)
Up-down counterValues you explicitly increase/decrease in codeconcurrent_requests (add 1 / add -1)
Observable gaugePolled values that can increase/decrease independentlyapplication_memory_usage (RSS/VMS polled by psutil)

Notes and best practices

  • Use rss (resident set size) to monitor actual memory resident in RAM. Use vms to inspect the total virtual address space requested by the process.
  • The callback receives an options parameter (not used in this example). Always return an iterable (e.g., a list) of Observation objects or (value, attributes) tuples.
  • The periodic exporter polls your observable callbacks at the configured interval (5 seconds in this example).
  • For production, run behind a proper WSGI server (e.g., Gunicorn, uWSGI) and replace the ConsoleMetricExporter with a production-ready exporter such as OTLP.
Do not use Flask’s development server in production. Configure a production WSGI server and a proper exporter (e.g., OTLP) for reliable metric delivery and performance.

Watch Video