Implementing OpenTelemetry Metrics in Python Apps
Modern applications demand robust observability solutions to monitor performance, detect bottlenecks, and ensure seamless user experiences.
OpenTelemetry has emerged as a powerful, standardized framework for capturing telemetry data — including traces, metrics, and logs — from distributed systems. By offering a unified approach to instrumentation, OpenTelemetry allows developers to track and visualize application health across complex architectures.
In this tutorial, we'll focus on implementing OpenTelemetry metrics in a Python
Flask application. Starting with the setup of the OpenTelemetry SDK, we'll
explore key metric types such as Counter, UpDownCounter, Gauge, and
Histogram.
You'll learn how to instrument your application to automatically track HTTP metrics, customize data aggregation, and configure efficient data collection and filtering. Finally, we'll cover how to send your metrics data to an OpenTelemetry Collector, allowing you to route it to a backend of your choice for analysis and visualization.
By the end of this guide, you'll have a comprehensive understanding of how to leverage OpenTelemetry metrics in Python, empowering you to gain actionable insights into your application's performance and health.
Let's get started!
Prerequisites
Before proceeding with this tutorial, you'll need to know the basics of metrics in OpenTelemetry.
Step 1 — Setting up the demo project
Let's start by creating a basic "Hello World" Flask server. Create a new directory for your project and navigate into it:
Now, create a virtual environment and activate it:
Next, install Flask and the necessary OpenTelemetry packages:
Let's create a simple Flask application. Create a file named app.py with the
following content:
Next, create a compose.yaml file to set up our services:
Create a Dockerfile for the Python application:
Create a requirements.txt file:
Create an .env file with basic configuration:
Finally, create an otelcol.yaml file for the OpenTelemetry Collector
configuration:
To launch both services, execute the command below:
You should see output indicating that both the Flask application and the OpenTelemetry Collector are running. To test the application, send a request to the root endpoint from a different terminal:
The response should be:
Now that the services are up and running, let's go ahead and set up the OpenTelemetry SDK.
Step 2 — Initializing the OpenTelemetry SDK
Before we can collect metrics, we need to initialize the OpenTelemetry SDK in
our Flask application. Update your app.py file with the following code:
This code sets up the OpenTelemetry SDK by:
- Configuring a
Resourcethat contains metadata about your application - Creating an OTLP exporter to send metrics to the OpenTelemetry Collector
- Setting up a
PeriodicExportingMetricReaderto export metrics every 3 seconds - Initializing a
MeterProviderwith your configured resource and reader - Setting the global meter provider so it can be accessed from anywhere in your code
Once these changes are saved, the Flask application will restart with OpenTelemetry configured. Now let's move on to automatic instrumentation for Flask.
Step 3 — Automatically instrument HTTP server metrics
OpenTelemetry provides automatic instrumentation for common libraries to help
you save time and focus on business-specific metrics. For Flask, we can use the
opentelemetry-instrumentation-flask package, which we've already installed
through our requirements.
Update your app.py file with the following code:
The key addition here is the FlaskInstrumentor().instrument_app(app) line,
which automatically adds instrumentation to your Flask application.
Once the changes are saved and the application restarts, the Flask instrumentation will automatically track HTTP metrics. The OpenTelemetry Collector logs will now show metrics for your Flask application including:
http.server.duration: Measures the duration of inbound HTTP requestshttp.server.request.size: Tracks the size of HTTP request messageshttp.server.response.size: Tracks the size of HTTP response messages
Send a request to the root endpoint to generate some metrics:
You should now see these metrics being logged by the collector.
Step 4 — Creating a Counter metric
Now, let's create custom metrics starting with a Counter metric. A Counter is
used to record a value that only increases. Let's track the total number of
requests to our Flask application.
Update your app.py file:
In this code, we create a meter using metrics.get_meter() and use it to create
a counter named http.server.requests. Every time the root endpoint is
accessed, we increment the counter by 1 and add the route as an attribute.
Send a request to the server:
You should now see the custom http.server.requests metric being logged by the
collector.
Step 5 — Creating an UpDownCounter metric
An UpDownCounter is similar to a Counter, but it allows the value to both
increase and decrease. This is perfect for tracking the number of active
requests.
Update your app.py file:
In this code, we've added an UpDownCounter called active_requests. When a
request is received, we increment the counter, and after processing the request,
we decrement it. This gives us a real-time count of in-progress requests.
Let's test this with some concurrent requests. You can use a tool like Apache Bench:
This command sends 100 requests with 10 concurrent connections. The
active_requests metric should show the number of active requests fluctuating.
Step 6 — Creating a Gauge metric
A Gauge in OpenTelemetry is used to record values that can go up and down, but
unlike an UpDownCounter, a Gauge is designed to track values that change
independently of previous measurements, like memory usage.
In Python, we can use an ObservableGauge to track memory usage:
Here, we use the psutil library to get the resident set size (RSS) of the
current process, which represents the memory usage. The
create_observable_gauge method sets up a gauge with a callback function that
will be called periodically to observe the current memory usage.
Make sure to install the psutil library:
Update your requirements.txt file to include psutil as well.
Step 7 — Creating and customizing Histograms
Histograms are useful for measuring the distribution of values, such as request durations. Let's create a histogram to measure the processing time of our request handler:
This creates a histogram named http.server.request.processing.duration that
records the time spent processing each request. By default, OpenTelemetry's
histograms use a predefined set of bucket boundaries, but you can customize them
if needed:
In OpenTelemetry Python, configuring custom bucket boundaries typically requires setting up a view through the SDK configuration, which is a bit more complex than directly specifying them when creating the histogram.
Final thoughts
In this tutorial, we explored the essentials of implementing OpenTelemetry
metrics in a Python Flask application. We covered setting up the OpenTelemetry
SDK, automatic instrumentation of HTTP server metrics, and creating custom
metrics including Counter, UpDownCounter, Gauge, and Histogram.
OpenTelemetry provides a unified framework for collecting and exporting telemetry data, making it easier to monitor and troubleshoot your applications. With the knowledge gained from this tutorial, you can implement comprehensive metrics collection in your Python applications, gaining valuable insights into their performance and health.
For next steps, you might want to explore distributed tracing with OpenTelemetry or dive deeper into creating custom dashboards and alerts in your chosen metrics backend. You could also look into more advanced configurations of the OpenTelemetry Collector to filter, transform, or enrich your telemetry data.
Thanks for reading, and happy monitoring!