• Home
  • Extend Dynatrace
  • Send data to Dynatrace with OpenTelemetry
  • OpenTelemetry traces
  • OpenTelemetry instrumentation guide
  • Instrument Python applications with OpenTelemetry

Instrument Python applications with OpenTelemetry

This guide shows how to instrument your Python application with OpenTelemetry and export the traces to Dynatrace.

  • To learn more about how Dynatrace works with OpenTelemetry, see Send data to Dynatrace with OpenTelemetry.
  • To learn how to export the metrics to Dynatrace with OpenTelemetry Instrument Python applications with OpenTelemetry Metrics.

Prerequisites

  • Dynatrace version 1.222+
  • Send W3C Trace Context HTTP headers is turned on (default setting). To verify this setting
    1. From the Dynatrace menu, go to Settings > Server-side service monitoring > Deep monitoring > Distributed tracing.
    2. Make sure Send W3C Trace Context HTTP headers is turned on.

Overview

To monitor your Python application with OpenTelemetry you need to

Instrument your application

Send the data to Dynatrace

Configure context propagation

Verify that the traces are ingested into Dynatrace

Configure data capture to meet privacy requirements

Instrument your application

You can use automatic instrumentation (provided by OpenTelemetry) or instrument manually.

To instrument automatically, go to the OpenTelemetry repository, find the framework that your app is using, and install the corresponding package using the following commands:

python
pip install opentelemetry-instrumentation pip install opentelemetry-instrumentation-<USED_FRAMEWORK>

Change the executable of your app to opentelemetry-instrument:

plaintext
opentelemetry-instrument python app.py
  • Note that, depending on your system, you might need to run python3 instead.

To instrument manually, install the OpenTelemetry SDK package and add the code snippet below to any Python method you want to monitor. Set names for the tracer, the span, and add attributes as you see fit.

python
pip install opentelemetry-sdk
python
from opentelemetry import trace as OpenTelemetry tracer = OpenTelemetry.get_tracer_provider().get_tracer("my-tracer") with tracer.start_as_current_span("my-span") as span: span.set_attribute("my-key-1", "my-value-1") #TODO your code goes here

Send data to Dynatrace

To send data to Dynatrace, you have to install the extra packages below, as well as add and configure the following code snippet in your Python application code:

python
pip install opentelemetry-sdk pip install opentelemetry-exporter-otlp-proto-http

With OneAgent, you can simply point to a local endpoint without an authentication token to enable trace ingestion.

python
import json from opentelemetry import trace as OpenTelemetry from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( OTLPSpanExporter, ) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider, sampling from opentelemetry.sdk.trace.export import ( BatchSpanProcessor, ) merged = dict() for name in ["dt_metadata_e617c525669e072eebe3d0f08212e8f2.json", "/var/lib/dynatrace/enrichment/dt_metadata.json"]: try: data = '' with open(name) as f: data = json.load(f if name.startswith("/var") else open(f.read())) merged.update(data) except: pass merged.update({ "service.name": "python-quickstart", #TODO Replace with the name of your application "service.version": "1.0.1", #TODO Replace with the version of your application }) resource = Resource.create(merged) tracer_provider = TracerProvider(sampler=sampling.ALWAYS_ON, resource=resource) OpenTelemetry.set_tracer_provider(tracer_provider) tracer_provider.add_span_processor( BatchSpanProcessor(OTLPSpanExporter( endpoint="http://localhost:14499/otlp/v1/traces" )))

When using OneAgent, make sure to enable the public Extension Execution Controller in your Dynatrace Settings, otherwise no data will be sent.

In the Dynatrace menu, go to Settings > Preferences > Extension Execution Controller. The toggles Enable Extension Execution Controller and Enable local PIPE/HTTP metric and Log Ingest API should be active.

Without OneAgent, you need to set the endpoint to a specific URL containing your environment ID, as well as configure an authentication token.

python
import json from opentelemetry import trace as OpenTelemetry from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( OTLPSpanExporter, ) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider, sampling from opentelemetry.sdk.trace.export import ( BatchSpanProcessor, ) merged = dict() for name in ["dt_metadata_e617c525669e072eebe3d0f08212e8f2.json", "/var/lib/dynatrace/enrichment/dt_metadata.json"]: try: data = '' with open(name) as f: data = json.load(f if name.startswith("/var") else open(f.read())) merged.update(data) except: pass merged.update({ "service.name": "python-quickstart", #TODO Replace with the name of your application "service.version": "1.0.1", #TODO Replace with the version of your application }) resource = Resource.create(merged) tracer_provider = TracerProvider(sampler=sampling.ALWAYS_ON, resource=resource) OpenTelemetry.set_tracer_provider(tracer_provider) tracer_provider.add_span_processor( BatchSpanProcessor(OTLPSpanExporter( endpoint="<URL>", #TODO Replace <URL> to your SaaS/Managed-URL as mentioned in the next step headers={ "Authorization": "Api-Token <TOKEN>" #TODO Replace <TOKEN> with your API Token as mentioned in the next step }, )))

Lastly, you need to define the correct endpoint and token, to make sure your data arrives where it should be.

  • To set the endpoint:
    1. Use your Environment ID to set the endpoint to which your app will send traces as follows:
      • Dynatrace SaaS https://{your-environment-id}.live.dynatrace.com/api/v2/otlp/v1/traces
      • Dynatrace Managed https://{your-domain}/e/{your-environment-id}/api/v2/otlp/v1/traces
      • Dynatrace ActiveGate https://{your-activegate-endpoint}/e/{your-environment-id}/api/v2/otlp/v1/traces
        • You may need to include the port to your ActiveGate endpoint. For example:
          • https://{your-activegate-endpoint}:9999/e/{your-environment-id}/api/v2/otlp/v1/traces
        • If you are running a containerized ActiveGate, you need to use the FQDN of it. For example:
          • https://{your-activegate-service-name}.dynatrace.svc.cluster.local/e/{your-environment-id}/api/v2/otlp/v1/traces
    2. Replace <URL> in the code snippet above with your endpoint.
  • To create an authentication token
    1. In the Dynatrace menu, go to Access tokens and select Generate new token.
    2. Provide a Token name.
    3. In the Search scopes box, search for Ingest OpenTelemetry traces and select the checkbox.
    4. Select Generate token.
    5. Select Copy to copy the token to your clipboard.
    6. Save the token in a safe place; you can't display it again.
    7. Replace <TOKEN> in the code snippet above with your token.

Configure context propagation optional

If you use manual instrumentation or a framework that is not supported by OpenTelemetry, you need to configure context propagation.

If your application receives a request or calls other applications, you need to configure context propagation to make sure the spans are linked together.

  • Whenever receiving an incoming request, you need to extract the parent context and create the new span as a child of it.
python
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator traceparent = request.headers.get_all("traceparent") carrier = {"traceparent": traceparent} ctx = TraceContextTextMapPropagator().extract(carrier) with tracer.start_as_current_span("my-span", context=ctx) as span: span.set_attribute("my-key-1", "my-value-1")
  • If your application calls another service, you need to ensure that you propagate the context, adding it to your outgoing request.
python
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator with tracer.start_as_current_span("my-span") as span: span.set_attribute("my-key-1", "my-value-1") try: carrier = {} TraceContextTextMapPropagator().inject(carrier) header = {"traceparent": carrier["traceparent"]} response = requests.get(url, headers=header) except Exception as e: pass

Verify that the traces are ingested into Dynatrace

A few minutes after restarting your app, look for your spans:

  • In the Dynatrace menu, go to Distributed traces and select the Ingested traces tab.
    • If you use OneAgent, go to Distributed traces and select the PurePaths tab.
  • Your spans will be part of an existing PurePath, if the root of your call is already monitored by OneAgent.

If your application does not receive any traffic, there will be no traces.

Configure data capture to meet privacy requirements optional

While Dynatrace automatically captures all OpenTelemetry resource and span attributes, only attribute values specified in the allowlist are stored and displayed in the Dynatrace web UI. This prevents accidental storage of personal data, so you can meet your privacy requirements and control the amount of monitoring data that's stored.

To view your custom span attributes, you need to allow them in the Dynatrace web UI first:

  • Span attributes In the Dynatrace menu, go to Settings and select Server-side service monitoring > Span attributes.
  • Resource attributes In the Dynatrace menu, go to Settings and select Server-side service monitoring > Resource attributes.