Adding observability to your applications is crucial for diagnosing issues in production. In this tutorial, you’ll learn how to integrate OpenTelemetry—an open-source observability framework—into a FastAPI application. After following along, you’ll be able to instrument FastAPI with OpenTelemetry to export traces and correlate them with your application logs, allowing you to explore your telemetry in a dedicated dashboard:

The image above previews the Jaeger UI that you’ll build toward over the course of this tutorial.
As your application grows, tracking down bugs across different services can become challenging. By adding observability, you gain clear insights into how your application performs and exactly where errors happen.
To achieve this, you’ll use OpenTelemetry, often called OTel. This vendor-neutral framework provides a standard way to collect telemetry data from your applications. It supports multiple programming languages, including Python, and exports data to various backends like Jaeger, Prometheus, and Grafana.
For this tutorial, you’ll use Jaeger, a popular open-source backend, to visualize your data. Together, OpenTelemetry and Jaeger let you analyze request paths, troubleshoot errors, and understand system bottlenecks.
Prerequisites
To follow along with this tutorial, you’ll need a couple of tools on your system:
- Python 3.10 or higher
- Docker to run the Jaeger backend container
Even if you’re new to Docker, you’ll only run a single command to start a ready-made container, and this tutorial walks you through it. If you’d like to go deeper, then you can explore the Docker tutorials later.
You should also be comfortable with a basic FastAPI app. If you need a refresher on the framework, then check out the introductory guide to get started with FastAPI. If you prefer learning by video, Real Python’s Start Building With FastAPI course covers the same essentials.
You can download the complete source code for the examples in this tutorial to use as a reference:
Get Your Code: Click here to download the free sample code you’ll use to instrument a FastAPI app with OpenTelemetry, exporting traces to a Jaeger backend, adding custom spans, correlating logs with traces, and tuning sampling.
Take the Quiz: Test your knowledge with our interactive “How to Integrate OpenTelemetry With a FastAPI App” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
How to Integrate OpenTelemetry With a FastAPI AppInstrument a FastAPI app with OpenTelemetry to export traces, add custom spans, and correlate your application logs with traces.
Step 1: Build Your FastAPI OpenTelemetry Pipeline
To begin, you need a backend to receive and display your traces. Jaeger’s all-in-one Docker image bundles everything into a single container for local development.
Open your terminal and start the Jaeger container using Docker:
$ docker run -d --name jaeger \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
jaegertracing/all-in-one:latest
This command launches Jaeger in the background. The port mappings each serve a distinct purpose. Port 16686 exposes the web UI that you’ll use to explore your traces, while ports 4317 and 4318 accept incoming telemetry via the OpenTelemetry Protocol (OTLP) over gRPC and HTTP, respectively. Keeping these apart matters later because your application will send data to an OTLP port, and you’ll view the results on the UI port.
Next, you’ll install the FastAPI framework along with the OpenTelemetry libraries. Before you do, create and activate a virtual environment so that the packages don’t end up in your system Python:
With your virtual environment active, install the packages. You’ll need the core OpenTelemetry distribution, the specific FastAPI instrumentation package, and the OTLP exporter to send your data to Jaeger:
(venv) $ python -m pip install fastapi uvicorn \
opentelemetry-distro \
opentelemetry-instrumentation-fastapi \
opentelemetry-exporter-otlp
Now that the tools are installed, you can build your application. Create a file named main.py and add the following code: