OpenTelemetry Tracing API for Python

Installation

OpenTelemetry-Python is the Python implementation of OpenTelemetry. It provides OpenTelemetry Tracing API which you can use to instrument your application with OpenTelemetry tracing.

shell
pip install opentelemetry-api

Quickstart

Step 1. Let's instrument the following function:

python
def insert_user(**kwargs):
    return User.objects.create_user(**kwargs)

Step 2. Wrap the operation with a span:

python
from opentelemetry import trace

tracer = trace.get_tracer("app_or_package_name", "1.0.0")

def insert_user(**kwargs):
    with tracer.start_as_current_span("insert-user") as span:
        return User.objects.create_user(**kwargs)

Step 3. Record contextual information with attributes:

python
def insert_user(**kwargs):
    with tracer.start_as_current_span("insert-user") as span:
        if span.is_recording():
            span.set_attribute("enduser.id", kwargs["id"])
            span.set_attribute("enduser.email", kwargs["email"])
        return User.objects.create_user(**kwargs)

And that's it! You don't have to manually record exceptions, because tracer.start_as_current_span does that automatically for you.

Tracer

To start creating spans, you need a tracer. You can create a tracer by providing the name and version of the library/application doing the instrumentation:

python
from opentelemetry import trace

tracer = trace.get_tracer("app_or_package_name", "1.0.0")

You can have as many tracers as you want, but usually you need only one tracer for an app or a library. Later, you can use tracer names to identify the instrumentation that produces the spans.

Creating spans

Once you have a tracer, creating spans is easy:

python
# Create a span with name "operation-name" and kind="server".
with tracer.start_as_current_span("operation-name", kind=trace.SpanKind.SERVER) as span:
    do_some_work()

Adding span attributes

To record contextual information, you can annotate spans with attributes. For example, an HTTP endpoint may have such attributes as http.method = GET and http.route = /projects/:id.

python
# To avoid expensive computations, check that span is recording
# before setting any attributes.
if span.is_recording():
    span.set_attribute("http.method", "GET")
    span.set_attribute("http.route", "/projects/:id")

You can name attributes as you want, but for common operations you should use semantic attributes convention.

Adding span events

You can annotate spans with events, for example, you can use events to record log messages:

python
span.add_event("log", {
    "log.severity": "error",
    "log.message": "User not found",
    "enduser.id": "123",
})

Setting status code

You can set error status code to indicate that the operation contains an error:

python
except ValueError as exc:
    span.set_status(trace.Status(trace.StatusCode.ERROR, str(exc)))

Recording exceptions

OpenTelemetry provides a shortcut to record exceptions which is usually used together with set_status:

python
except ValueError as exc:
    # Record the exception and update the span status.
    span.record_exception(exc)
    span.set_status(trace.Status(trace.StatusCode.ERROR, str(exc)))

Context

OpenTelemetry stores the active span in a context and saves the context in a thread-local storage. You can nest contexts inside each other and OpenTelemetry will automatically activate the parent span context when you end the span.

start_as_current_span sets the active span for you, but you can also activate the span manually:

python
# Activate the span in the current context.
with trace.use_span(span, end_on_exit=True):
    do_some_work()

To get the active span from the current context:

python
from opentelemetry import trace

span = trace.get_current_span()

If you are using distributed services, you can propagate context to another service using OpenTelemetry requests instrumentation.

Auto-instrumentation

opentelemetry-python allows you to automatically instrument any Python app using opentelemetry-instrument utility from opentelemetry-instrumentation package.

First, you need to install the opentelemetry-instrument executable:

shell
pip install opentelemetry-instrumentation

Then, install instrumentations that should be applied automatically by opentelemetry-instrument:

shell
pip install opentelemetry-instrumentation-flask

And run you app using opentelemetry-instrument wrapper:

shell
UPTRACE_DSN="<FIXME>" opentelemetry-instrument python3 main.py

See flask-auto-instrumentation example for full details.

How auto-instrumentation works?

uptrace-python registers an OpenTelemetry distro using an entry point in setup.cfg. Instrumentations register themselves using the same mechanism. OpenTelemetry then just calls the code specified in entry points to configure OpenTelemetry SDK and instrument the code.

OpenTelemetry APM

Uptrace is a Grafana alternative that supports distributed tracing, metrics, and logs. You can use it to monitor applications and troubleshoot issues.

Uptrace comes with an intuitive query builder, rich dashboards, alerting rules with notifications, and integrations for most languages and frameworks.

Uptrace can process billions of spans and metrics on a single server and allows you to monitor your applications at 10x lower cost.

In just a few minutes, you can try Uptrace by visiting the cloud demo (no login required) or running it locally with Docker. The source code is available on GitHub.

What's next?