Integrating OpenTelemetry with FastAPI in Python For Observability

Monitoring and analyzing your apps' performance is critical for ensuring dependability in production scenarios. OpenTelemetry (OTEL) is a contemporary, open-source framework that enables you to gather and export telemetry data (traces, metrics, and logs) to various backends, including Jaeger, Zipkin, and cloud platforms.

This post will show how to combine OpenTelemetry with a basic FastAPI application to begin tracking incoming request traces. We'll keep things simple by allowing basic observability features.

Prerequisites

Before we begin, ensure you have the following:

  • A basic FastAPI app (if you don’t, refer to this guide on setting up FastAPI or clone the GitHub repo).
  • Python 3.8+.
  • Poetry for dependency management.

Step 1: Installing OpenTelemetry Packages

We need to install some OpenTelemetry packages to set up our tracing infrastructure. Activate your Poetry environment and install these packages with the following command:

poetry add opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp \
           opentelemetry-instrumentation-fastapi

This command installs:

  • opentelemetry-api: Core API for OpenTelemetry, providing a foundation for tracing.
  • opentelemetry-sdk: The implementation of OpenTelemetry APIs, enabling trace creation and processing.
  • opentelemetry-exporter-otlp: The OpenTelemetry protocol exporter sends telemetry data to an OpenTelemetry Collector.
  • opentelemetry-instrumentation-fastapi: Automatically instruments FastAPI applications to capture traces.

Step 2: Basic FastAPI Setup

Here’s a basic FastAPI app to start:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello, World!"}

This simple application will be our foundation for adding OpenTelemetry. Run it with:

uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1

When you visit localhost:8000, you’ll see:

"Hello World" message returned in the local host

Step 3: Setting Up an OpenTelemetry Collector

To export telemetry data, we need an OpenTelemetry Collector. You can run the collector locally (e.g., using Docker or another container service) or deploy it in your production environment.

Run the Collector Locally:

  • You can use the OpenTelemetry Collector image from Docker Hub.
  • Set it up to listen on port 4317, which our app will use to send traces.

For example, if you’re using Docker:

docker run --name otel-collector -p 4317:4317 -v $(pwd)/otel-config.yaml:/etc/otel/config.yaml otel/opentelemetry-collector --config /etc/otel/config.yaml

Replace otel-config.yaml with your preferred configuration for the collector.

Step 4: Integrating OpenTelemetry with FastAPI

To enable OpenTelemetry tracing, we’ll need to set up a global tracer in our FastAPI app.

4.1) Create a tracer.py File:

In this file, we’ll initialize an OpenTelemetry tracer to capture and export traces for each request made to our FastAPI app.

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import ConsoleSpanExporter  # Optional for debugging

SERVICE_NAME = 'fastapi'
OTLP_COLLECTOR_ENDPOINT = ""

# Initialize OpenTelemetry Tracer globally
def initialize_tracer():
    # Create a resource for trace identification with service info
    resource = Resource.create({"service.name": SERVICE_NAME})

    # Set up the TracerProvider, the root of all tracing
    tracer_provider = TracerProvider(resource=resource)

    # Configure the OTLP Exporter to send traces to the OpenTelemetry Collector
    otlp_exporter = OTLPSpanExporter(endpoint=OTLP_COLLECTOR_ENDPOINT)
    span_processor = BatchSpanProcessor(otlp_exporter)
    tracer_provider.add_span_processor(span_processor)

    # Optional: Add a ConsoleSpanExporter for local debugging
    console_processor = BatchSpanProcessor(ConsoleSpanExporter())
    tracer_provider.add_span_processor(console_processor)

    # Set the global TracerProvider
    trace.set_tracer_provider(tracer_provider)

# Initialize the tracer when the module loads
initialize_tracer()

# Function to get the global OpenTelemetry Tracer
def get_tracer():
    return trace.get_tracer(SERVICE_NAME)

Explanation of Code:

  • Service Name: We set SERVICE_NAME to identify the service sending traces.
  • Resource: Defines metadata about the service (e.g., name), making it easy to track where traces come from.
  • TracerProvider: The central object responsible for creating and managing tracers. We initialize it with our service metadata.
  • OTLPSpanExporter: An exporter that sends collected traces to the OpenTelemetry Collector over HTTP. We configure it with the OTLP_COLLECTOR_ENDPOINT, pointing to our collector.
  • BatchSpanProcessor: Ensures spans are batched before export, optimizing network calls.
  • ConsoleSpanExporter (Optional): Exports spans to the console, applicable for local debugging.

4.2) Modify the FastAPI App to Use OpenTelemetry:

Now, we’ll add OpenTelemetry instrumentation to our FastAPI app. Open your main.py file and update it as follows:

from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from tracer import initialize_tracer

# Initialize the tracer
initialize_tracer()

app = FastAPI()

# Instrument FastAPI with OpenTelemetry
FastAPIInstrumentor.instrument_app(app)

@app.get("/")
def read_root():
    return {"message": "Hello, World!"}

Explanation of Code:

  • initialize_tracer(): Initializes the global tracer when the app starts.
  • FastAPIInstrumentor.instrument_app(app): Automatically instruments the FastAPI app to capture traces for all requests. This will monitor each route's request/response lifecycle and send trace data to the OpenTelemetry Collector.

Step 5: Running the FastAPI App

With everything configured, start your FastAPI app with:

uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1

Testing the Traces

  • Open a browser or use curl to test the FastAPI endpoint:
curl 
  • You should see the response:
{"message": "Hello, World!"}
  • Your terminal should show the following:
Successful integration of OpenTelemetry into FastAPI
Successful integration of OpenTelemetry into FastAPI

Conclusion

That is it! You have successfully incorporated OpenTelemetry into your FastAPI program, and traces may now be sent to an OpenTelemetry collector. This configuration provides basic observability, allowing you to track requests across your system and troubleshoot problems in distributed systems.

As your application grows, you may add more OpenTelemetry exporters, metrics, and logs to improve observability.

Read More:


Integrating OpenTelemetry with FastAPI in Python For Observability

Written By Shrawan Sunar

Nov 27, 2024

Shrawan Sunar is a seasoned software engineer with a robust background in software development, system architecture, and application design. With extensive experience in multiple programming languages and modern frameworks, Shrawan has a proven track record of building scalable, high-performance applications that drive digital innovation and enhance user experiences for businesses. His expertise lies in crafting efficient, maintainable codebases and ensuring seamless integration of software solutions across diverse platforms. A results-oriented developer, Shrawan is dedicated to improving software quality and fostering innovation in every project he undertakes.

Latest Blogs

Recent Development In AWS: April 2025

AWS continues to roll out meaningful improvements, and the updates for April 2025 are no exception....


Chandra Rana

May 02, 2025

Outsourced IT Services for Small Business

With limited in-house resources and growing technology demands, small and medium-sized businesses (S...


Adex International

Apr 30, 2025

Docker Bridge Networking: In-Depth Guide to Setup, Connection, and Troubleshooting

Docker has changed the way we build and run applications by using lightweight, portable containers....


Ujwal Budha

Apr 30, 2025