Last9 Last9

Feb 18th, ‘25 / 9 min read

A Quick Guide for OpenTelemetry Python Instrumentation

Learn how to instrument your Python applications with OpenTelemetry to gain insights, track performance, and troubleshoot issues effectively.

A Quick Guide for OpenTelemetry Python Instrumentation

OpenTelemetry is an open-source tool that helps you keep an eye on your application’s performance.

Whether you’re building microservices, using serverless setups, or working with a traditional monolithic app, it’s crucial to monitor and trace your app’s behavior for debugging and optimization. OpenTelemetry's Python instrumentation is an excellent way to track traces, metrics, and logs across your entire app.

In this guide, we’ll take a close look at how to use OpenTelemetry with Python, from getting started with installation to diving into more advanced configurations. By the end, you’ll have a solid grasp of how to instrument your Python code, giving you deeper insights into your app’s performance and behavior. Let's break it all down so it’s easy to follow and apply to your projects.

What is OpenTelemetry?

Before we get into the specifics of Python instrumentation, it’s important to understand what OpenTelemetry is and why it matters.

OpenTelemetry is a set of APIs, libraries, agents, and instrumentation that allow you to collect telemetry data—such as traces, metrics, and logs—from applications and services. The project is a merger of OpenTracing and OpenCensus, combining the best features of both frameworks to provide a unified, vendor-agnostic solution for observability.

The goal of OpenTelemetry is to standardize the way we collect telemetry data, making it easier to monitor, troubleshoot, and optimize applications across different environments.

Why Use OpenTelemetry for Python?

Python is widely used for building web applications, data processing pipelines, APIs, and more. With OpenTelemetry, Python developers can gain visibility into how their applications behave in real time.

Here's why you should consider using OpenTelemetry in your Python projects:

  • Standardized Observability: OpenTelemetry enables you to instrument your Python code without worrying about vendor lock-in. You can send telemetry data to a variety of backends (like Prometheus, Jaeger, or Zipkin) and easily switch between them.
  • Comprehensive Telemetry: OpenTelemetry provides tracing, metrics, and logs, allowing you to track performance bottlenecks, diagnose issues, and monitor application health in real-time.
  • Low Overhead: The OpenTelemetry Python SDK is designed with performance in mind, ensuring that the overhead of instrumentation is minimal and doesn’t impact the behavior of your application.
  • Extensive Ecosystem: OpenTelemetry supports various frameworks, libraries, and services in the Python ecosystem. Whether you’re using Flask, Django, or FastAPI, there's support for automatic instrumentation.
💡
For more on handling OTLP headers and troubleshooting with OpenTelemetry, check out our detailed guide on whitespace in OTLP headers here.

Getting Started with OpenTelemetry in Python

Let’s get your hands dirty with some code. To use OpenTelemetry in a Python project, the first step is to install the required packages.

Step 1: Install the OpenTelemetry Python SDK

First things first, you need to install the core OpenTelemetry packages. You can easily do this using pip by running the following command:

pip install opentelemetry-api opentelemetry-sdk

This installs the core OpenTelemetry API and SDK libraries. Depending on the type of telemetry data you want to collect—such as tracing, metrics, or logs—you might also need to install additional packages.

Step 2: Setting Up OpenTelemetry Tracing in Your Application

Now that we have OpenTelemetry installed, it’s time to set up tracing. Tracing helps you track the flow of requests or tasks through your application. Let’s break down how to do this:

2.1 Create a Tracer Provider

A Tracer Provider is the central part of the tracing setup. It manages the creation of spans, which are individual units of work tracked by OpenTelemetry.

2.2 Configure a Span Exporter

To send the trace data to a backend (like Last9, Jaeger or Zipkin), you need to configure an Exporter. The exporter takes the traces and sends them to your chosen backend for visualization and analysis.

2.3 Start Tracing with Spans: Sending Trace Data to Last9

Now, let’s set up tracing with Last9, a modern observability platform. We'll configure OpenTelemetry to send traces to Last9, which provides advanced monitoring and analysis capabilities.

First, ensure you have a Last9configured account and have set up the necessary configurations in your environment. Here’s how to integrate OpenTelemetry tracing with Last9.

Example of Sending Trace Data to Last9:

from opentelemetry import trace
from opentelemetry.exporter.last9 import Last9Exporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor

# Set up the tracer provider and exporter
trace.set_tracer_provider(TracerProvider())
last9_exporter = Last9Exporter(
    endpoint="https://your-last9-endpoint.com/api/v1/spans",
    api_key="your-api-key"
)
span_processor = SimpleSpanProcessor(last9_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

# Get the tracer
tracer = trace.get_tracer(__name__)

# Create a span
with tracer.start_as_current_span("example-span"):
    print("This is a traced span sent to Last9")

In this example:

  • We set up the tracer provider and configured the Last9 Exporter to send trace data to Last9’s endpoint.
  • Replace your-last9-endpoint.com with your actual Last9 endpoint and provide the correct api_key for authentication.
  • The span is created using the start_as_current_span context manager, tracking the code execution inside the block.

With this setup, traces from your application will be sent to Last9 for deeper insights into your system’s behavior. You can monitor and troubleshoot your application’s performance in real time, all through Last9’s intuitive UI.

💡
This integration works similarly to Jaeger or Zipkin, but with Last9 - a telemetry data platform for high cardinality observability, you get more tailored features and a platform built specifically to handle modern observability challenges.

Step 3: Exporting Traces to Your Chosen Backend

Now that your traces are set up, the next step is to export them to a backend for visualization and analysis. OpenTelemetry supports multiple backends, such as Jaeger, Zipkin, and others. In this case, we’ll focus on exporting traces to Last9 for modern observability.

Here’s how you can easily replace the Jaeger exporter with Last9 in your OpenTelemetry setup:

Example: Exporting Traces to Last9

from opentelemetry import trace
from opentelemetry.exporter.last9 import Last9Exporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor

# Set up the tracer provider and exporter
trace.set_tracer_provider(TracerProvider())
last9_exporter = Last9Exporter(
    endpoint="https://your-last9-endpoint.com/api/v1/spans",
    api_key="your-api-key"
)
span_processor = SimpleSpanProcessor(last9_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

# Get the tracer
tracer = trace.get_tracer(__name__)

# Create a span
with tracer.start_as_current_span("example-span"):
    print("This is a traced span sent to Last9")

One of the coolest features of OpenTelemetry is automatic instrumentation. This feature automatically adds tracing to popular libraries and frameworks, such as Flask, Django, and FastAPI, without needing to manually instrument your code.

To enable automatic instrumentation, you’ll need to install the opentelemetry-instrumentation package:

pip install opentelemetry-instrumentation

Once installed, you can instrument your web application like this:

from opentelemetry.instrumentation.flask import FlaskInstrumentor

# Instrument your Flask app
FlaskInstrumentor().instrument_app(app)

This will automatically create spans for incoming HTTP requests, giving you visibility into how each request is processed by your Flask app. You can use the same approach for other frameworks and libraries, such as SQLAlchemy for database queries, Redis for caching, and more.

With automatic instrumentation, you don't have to manually add spans around every HTTP request or database query—OpenTelemetry handles that for you, saving you time and effort.

💡
For a deeper dive into using Jaeger with OpenTelemetry, be sure to check out our step-by-step guide here.

Advanced OpenTelemetry Python Instrumentation

Once you’ve mastered the basics, it’s time to explore some of the more advanced features of OpenTelemetry in Python. These tools will help you gain more granular insights into your application’s performance and behavior, enabling you to monitor custom operations, track metrics, and handle errors more effectively.

How to Create Custom Traces for Tracking Specific Operations

In some cases, you may want to create custom spans to track specific parts of your application, beyond the automatic tracing of web requests.

OpenTelemetry allows you to define your own spans using the start_span method, giving you complete control over how and where you track performance.

Here’s an example of how you can create custom spans, set attributes, and add events to your traces:

with tracer.start_span("custom-span") as span:
    span.set_attribute("example.attribute", "value")
    span.add_event("event_description")
    # Do some work...

In this example:

  • We create a custom span called custom-span.
  • We add an attribute (example.attribute) to provide additional context about the span.
  • We also add an event (event_description) that logs a specific occurrence during the span’s lifetime.

Custom tracing is particularly useful for tracking specific business logic, background tasks, or any operation that is not automatically captured by frameworks or libraries.

How Can Metrics and Logs Enhance Your Observability?

OpenTelemetry isn’t just for tracing; it also supports collecting metrics and logs, which are essential for understanding the health and performance of your application.

By tracking things like request rates, error counts, and system resource usage, you can gather a more complete view of how your system is behaving.

How Do You Set Up Metrics to Monitor Your Application?

Metrics are collected using the Meter API. Here’s an example of how to set up a metric to count the number of requests processed:

from opentelemetry.sdk.metrics import Counter, MeterProvider

# Set up metrics
meter_provider = MeterProvider()
counter = meter_provider.get_meter(__name__).create_counter(
    "requests_count", "Number of requests processed", int
)

# Record a metric
counter.add(1)

In this example:

  • We create a Counter metric called requests_count to track the number of requests processed.
  • The counter.add(1) line increments the count by 1 every time a request is processed.

How to Capture Logs

OpenTelemetry also provides a Logger API to capture logs alongside your metrics and traces. Here’s an example of logging a request processing event:

from opentelemetry.sdk.logs import LoggerProvider

# Set up logs
logger_provider = LoggerProvider()
logger = logger_provider.get_logger(__name__)

# Record a log
logger.info("Request processed successfully")

With this setup, you can capture logs at various levels (info, error, debug, etc.) to give more context to your traces and metrics. This is especially useful for diagnosing issues and understanding the flow of requests through your system.

How Distributed Tracing Works with Opentelemetry

In a distributed system, where multiple services interact with one another, it’s important to track the flow of requests as they move through these services. OpenTelemetry makes this easy with distributed tracing, which allows you to track the entire lifecycle of a request as it propagates through different microservices.

OpenTelemetry automatically propagates the trace context across service boundaries. This means that even if a request travels through several different services, the traces will be correlated, and you can track the request’s journey through the system in a single, unified trace.

💡
To learn more about tracking requests across multiple services, check out our guide on distributed tracing with OpenTelemetry.

How to Track Errors and Status Codes in Your Application

One of the key benefits of OpenTelemetry is its ability to track errors and provide context about failures in your application. By using span status codes, you can mark spans as errors and include relevant details about the issue.

Here’s an example of how to track errors during operations:

from opentelemetry.sdk.trace import Status, StatusCode

with tracer.start_span("operation"):
    try:
        # Perform some operation that might fail
        result = risky_operation()
    except Exception as e:
        span.set_status(Status(StatusCode.ERROR, str(e)))
        raise

In this example:

  • We create a span around a risky operation.
  • If the operation fails (throws an exception), we set the span status to ERROR and include the exception message as additional context.

This approach ensures that failures are properly recorded and provides the necessary context to troubleshoot issues. With this information, you can quickly identify errors and understand their impact on your system.

Conclusion

OpenTelemetry provides Python developers with a powerful, flexible framework to monitor and troubleshoot their applications.

In this guide, we’ve covered everything from setting up OpenTelemetry to advanced techniques like custom spans, metrics, and error handling.

💡
But, if you’d like to dive deeper or have any questions, feel free to join our community on Discord. We have a dedicated channel where you can connect with other developers and discuss your specific use case.

FAQs

1. What is OpenTelemetry and why should I use it in Python?

OpenTelemetry is an open-source framework that provides a set of APIs and libraries for collecting telemetry data—such as traces, metrics, and logs—from applications. By integrating OpenTelemetry into your Python application, you can monitor performance, diagnose issues, and gain visibility into how your code is behaving in production.

2. How do I install OpenTelemetry in my Python project?

To install OpenTelemetry in your Python project, use pip to install the core SDK and API:

pip install opentelemetry-api opentelemetry-sdk

Depending on your needs (e.g., tracing, metrics, logs), you might need to install additional instrumentation packages.

3. What types of telemetry data can OpenTelemetry capture?

OpenTelemetry can capture three main types of telemetry data:

  • Traces: Track the flow of requests through your application and provide insight into performance bottlenecks.
  • Metrics: Monitor system performance metrics like request counts, latency, error rates, etc.
  • Logs: Capture log data to provide additional context for tracing and metrics, useful for debugging and troubleshooting.

4. How do I set up tracing in Python using OpenTelemetry?

To set up tracing, you need to create a tracer provider and configure an exporter to send trace data to a backend (e.g., Last9, Jaeger, Zipkin). Here's a basic example for tracing with Jaeger:

from opentelemetry import trace
from opentelemetry.exporter.jaeger import JaegerExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor

# Set up the tracer provider and exporter
trace.set_tracer_provider(TracerProvider())
jaeger_exporter = JaegerExporter(agent_host_name='localhost', agent_port=5775)
span_processor = SimpleSpanProcessor(jaeger_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

# Create a span
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("example-span"):
    print("This is a traced span")

5. Can I export traces to different backends like Jaeger or Last9?

Yes, OpenTelemetry supports exporting traces to various backends, including Jaeger, Zipkin, Last9 and more. You can configure the exporter to send trace data to your desired backend by setting up the corresponding exporter in your code (e.g., JaegerExporter, ZipkinExporter, etc.).

6. What are automatic instrumentation and how do I enable it for Python web frameworks like Flask or Django?

Automatic instrumentation in OpenTelemetry allows you to easily add tracing and monitoring to popular libraries and frameworks (like Flask, Django, and FastAPI) without modifying application code. To enable automatic instrumentation, you can install the opentelemetry-instrumentation package and then use it to instrument your app:

pip install opentelemetry-instrumentation

For example, for Flask:

from opentelemetry.instrumentation.flask import FlaskInstrumentor

FlaskInstrumentor().instrument_app(app)

7. How do I track errors and set status codes for spans in OpenTelemetry?

OpenTelemetry allows you to track errors by setting the span’s status to ERROR. If an operation fails, you can mark the span with an error status to capture the failure:

from opentelemetry.sdk.trace import Status, StatusCode

with tracer.start_span("operation"):
    try:
        result = risky_operation()
    except Exception as e:
        span.set_status(Status(StatusCode.ERROR, str(e)))
        raise

Contents


Newsletter

Stay updated on the latest from Last9.

Authors
Prathamesh Sonpatki

Prathamesh Sonpatki

Prathamesh works as an evangelist at Last9, runs SRE stories - where SRE and DevOps folks share their stories, and maintains o11y.wiki - a glossary of all terms related to observability.

X