Pyroscope OpenTelemetry Python Integration
The `pyroscope-otel` library for Python provides functionalities to link OpenTelemetry tracing data with Grafana Pyroscope's continuous profiling data. It offers a `SpanProcessor` implementation that automatically attaches profiling identifiers to trace spans, enabling users to correlate traces with detailed performance profiles. The library is actively maintained by Grafana, with its current version being 1.0.0. Releases appear to be somewhat regular, reflecting ongoing development.
Warnings
- gotcha The `pyroscope-otel` package requires both the base `pyroscope` profiler and OpenTelemetry tracing to be instrumented in your application. It acts as a bridge, not a standalone profiler or tracer. You must explicitly install and configure both prerequisites.
- gotcha The `pyroscope.configure()` function must be called and executed *before* any OpenTelemetry `TracerProvider` is created and the `PyroscopeSpanProcessor` is registered. Incorrect ordering can lead to profiling data not being correctly associated with traces.
- gotcha Due to the nature of sampling profilers, trace spans that are very short in duration (e.g., less than the profiler's sample interval, typically 10ms for a 100 samples/second CPU profiler) may not be captured or linked with profiling data. This is a limitation of the profiling technique.
- breaking The OpenTelemetry profiles signal specification is under active development. This means that breaking changes can occur in related components (profilers, collectors, SDKs), potentially requiring careful version management and updates to maintain compatibility across your observability stack.
- gotcha Currently, `pyroscope-otel` for Python primarily supports CPU profiling. Other profiling types (e.g., memory) available in Pyroscope might not be integrated with OpenTelemetry traces via this package.
Install
-
pip install pyroscope-otel
Imports
- PyroscopeSpanProcessor
from pyroscope.otel import PyroscopeSpanProcessor
- configure
from pyroscope import configure as pyroscope_configure
- TracerProvider
from opentelemetry.sdk.trace import TracerProvider
Quickstart
import os
import time
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
from pyroscope import configure as pyroscope_configure
from pyroscope.otel import PyroscopeSpanProcessor
# 1. Configure Pyroscope profiler first
pyroscope_configure(
app_name="my-python-app",
server_address=os.environ.get("PYROSCOPE_SERVER_ADDRESS", "http://localhost:4040"),
auth_token=os.environ.get("PYROSCOPE_AUTH_TOKEN", ""), # Optional for Grafana Cloud
sample_rate=100, # Default sample rate
)
# 2. Configure OpenTelemetry TracerProvider
provider = TracerProvider()
# Add PyroscopeSpanProcessor to link traces and profiles
provider.add_span_processor(PyroscopeSpanProcessor())
# Optional: Add a console exporter for visibility of spans
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
# 3. Get a tracer and create spans
tracer = trace.get_tracer(__name__)
def my_function():
with tracer.start_as_current_span("my-function-span") as span:
print("Executing my_function...")
time.sleep(0.05)
with tracer.start_as_current_span("inner-operation"):
print("Executing inner_operation...")
time.sleep(0.02)
print("my_function finished.")
if __name__ == "__main__":
print("Starting application with Pyroscope-OpenTelemetry integration...")
my_function()
print("Application finished.")
# Give some time for exporters to send data
time.sleep(1)