Instrument your Python application with OpenTelemetry to report trace data to Managed Service for OpenTelemetry. Once connected, Application Real-Time Monitoring Service (ARMS) displays application topology, traces, abnormal transactions, slow transactions, and SQL analysis.
This topic covers three instrumentation approaches:
Automatic instrumentation -- No code changes. An OpenTelemetry agent instruments supported frameworks at runtime.
Manual instrumentation -- Full control. Add spans, attributes, and baggage through the OpenTelemetry SDK.
Combined instrumentation -- Layer custom spans on top of automatic instrumentation for targeted visibility.
Prerequisites
An endpoint and authentication token from the Managed Service for OpenTelemetry console. See Obtain access point information
Supported frameworks
OpenTelemetry provides automatic instrumentation plug-ins for common Python frameworks. The following table lists the supported frameworks and their version requirements. For the full list, see opentelemetry-python-contrib.
~= V.N means >= V.N and == V.*. For example, aiohttp ~= 3.0 means version 3.0 or later within the 3.x range.Sample code
Download the complete sample code from python-opentelemetry-demo.
Choose a transport protocol
Managed Service for OpenTelemetry accepts trace data over HTTP and gRPC. Choose based on your network environment.
| Protocol | Best for | Notes |
|---|---|---|
| HTTP | Most environments | Traverses proxies and firewalls easily. No authentication header required. |
| gRPC | Low-latency, high-throughput environments | Requires the grpcio package. Uses an Authentication header. |
Both options appear in the examples below. Choose one based on your network requirements.
Placeholder reference
Replace these placeholders in the examples with your actual values:
| Placeholder | Description | Where to find it |
|---|---|---|
<your-service-name> | Identifies your application in the ARMS console. | You define this. Example: my-python-app |
<host-name> | Hostname of the machine running your application. | Run hostname in your terminal. |
<endpoint> | Endpoint for reporting trace data (HTTP or gRPC). | Managed Service for OpenTelemetry console. See Obtain access point information. |
<token> | Authentication token (gRPC only). | Managed Service for OpenTelemetry console. See Obtain access point information. |
Automatic instrumentation
Automatic instrumentation is the quickest path to distributed tracing. The OpenTelemetry agent instruments supported frameworks at runtime without code changes.
Step 1: Install dependencies
pip install django
pip install requests
pip install opentelemetry-distro \
opentelemetry-exporter-otlp
opentelemetry-bootstrap -a installopentelemetry-bootstrap detects installed libraries and installs the matching instrumentation plug-ins automatically.
Step 2: Create a Django project and application
Create an AutoAndManualDemo project:
django-admin startproject AutoAndManualDemoCreate a HelloWorld application in the project:
cd AutoAndManualDemo # Create a HelloWorld application in the project. python manage.py startapp helloworld
Step 3: Add application code
Add the following code to the
AutoAndManualDemo/helloworld/views.pyfile:from django.http import HttpResponse from datetime import datetime # Create your views here. def hello_world_view(request): result = "Hello World! Current Time =" + str(get_time()) return HttpResponse(result) def get_time(): now = datetime.now() return now.strftime("%H:%M:%S")Create a
AutoAndManualDemo/helloworld/urls.pyfile and add the following code:from django.urls import path from . import views urlpatterns = [ path('', views.hello_world_view, name='helloworld') ]Add the URL pattern to the
AutoAndManualDemo/AutoAndManualDemo/urls.pyfile:from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('helloworld/', include('helloworld.urls')), ]
Step 4: Run your application
Prefix your start command with opentelemetry-instrument and pass the exporter configuration.
Report over HTTP
opentelemetry-instrument \
--traces_exporter console,otlp_proto_http \
--metrics_exporter none \
--service_name <your-service-name> \
--exporter_otlp_traces_endpoint <endpoint> \
python manage.py runserver --noreloadIf you do not want the console to display the trace data, set the --traces_exporter parameter to --traces_exporter otlp_proto_http.
- The
--noreloadflag prevents Django from running themanage.mainmethod twice. - If you see
CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False, set the environment variable before running: This error occurs becauseopentelemetry-instrumentloads the default Django settings file (django/conf/global_settings.py) instead of your project settings.
export DJANGO_SETTINGS_MODULE=AutoAndManualDemo.settingsStep 5: Verify trace reporting
Visit
http://127.0.0.1:8000/helloworld/in a browser. The console displays the trace data and reports the trace data to Managed Service for OpenTelemetry.Log on to the ARMS console.
In the left-side navigation pane, choose Application Monitoring > Applications.
On the Applications page, find your application by the service name you configured and click it.
On the application details page, verify that traces appear. You should see span data corresponding to the requests you sent.
icon appears in the Language column, the application is connected to Application Monitoring. A hyphen (-) indicates a connection to Managed Service for OpenTelemetry.Manual instrumentation
Use manual instrumentation for fine-grained control over spans, attributes, and context propagation. This approach adds OpenTelemetry SDK calls directly to your code.
Step 1: Install dependencies
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlpStep 2: Initialize OpenTelemetry
Create an initialization module (for example, manual.py) that configures the tracer provider and exporter.
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
OTLPSpanExporter as OTLPSpanGrpcExporter,
)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
OTLPSpanExporter as OTLPSpanHttpExporter,
)
from opentelemetry.sdk.resources import SERVICE_NAME, HOST_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
def init_opentelemetry():
resource = Resource(attributes={
SERVICE_NAME: "<your-service-name>",
HOST_NAME: "<host-name>",
})
# Option A: Export over gRPC
span_processor = BatchSpanProcessor(OTLPSpanGrpcExporter(
endpoint="<endpoint>",
headers=("Authentication=<token>"),
))
# Option B: Export over HTTP (uncomment to use)
# span_processor = BatchSpanProcessor(OTLPSpanHttpExporter(
# endpoint="<endpoint>",
# ))
trace_provider = TracerProvider(
resource=resource,
active_span_processor=span_processor,
)
trace.set_tracer_provider(trace_provider)Step 3: Create spans
After initialization, obtain a tracer and create spans to track operations.
tracer = trace.get_tracer(__name__)
# Context manager pattern
with tracer.start_as_current_span("child_span") as child_span:
print("hello world")Nest spans to represent parent-child relationships:
def outer_method():
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("parent_span") as parent_span:
inner_method()
def inner_method():
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("child_span") as child_span:
print("hello world")Step 4: Retrieve the trace ID and span ID
Extract the trace ID and span ID from the current span context. These IDs are useful for correlating logs with traces.
ctx = trace.get_current_span().get_span_context()
trace_id = '{trace:032x}'.format(trace=ctx.trace_id)
span_id = '{span:016x}'.format(span=ctx.span_id)
print(trace_id)
print(span_id)Step 5: Propagate custom metadata with the Baggage API
The OpenTelemetry Baggage API propagates key-value pairs across spans within a trace. Use baggage to pass metadata -- such as user IDs, tenant IDs, or request context -- between services.
from opentelemetry import trace, baggage
def baggage_and_attribute_usage():
tracer = trace.get_tracer(__name__)
# Set baggage at the global level
global_ctx = baggage.set_baggage("key", "value_from_global_ctx")
# Create a span with custom attributes
with tracer.start_as_current_span(
name='baggage_parent_span',
attributes={'attribute_key': 'value'},
) as baggage_parent_span:
# Set baggage in the parent context
parent_ctx = baggage.set_baggage("key", "value_from_parent_ctx")
with tracer.start_as_current_span(
name='baggage_child_span',
context=parent_ctx,
) as baggage_child_span:
# Set baggage in the child context
child_ctx = baggage.set_baggage("key", "value_from_child_ctx")
# Read baggage values from each context
print(baggage.get_baggage("key", global_ctx)) # value_from_global_ctx
print(baggage.get_baggage("key", parent_ctx)) # value_from_parent_ctx
print(baggage.get_baggage("key", child_ctx)) # value_from_child_ctxStep 6: Run and verify
python manual.pyAfter the application runs, verify trace data in the ARMS console. Follow the steps in the Verify trace reporting section under Automatic instrumentation.
Combined instrumentation
Combine automatic and manual instrumentation to get broad framework coverage from the agent while adding custom spans for business-critical operations. This approach uses the auto-instrumentation agent for framework-level tracing, and adds SDK calls for application-specific spans.
Step 1: Install dependencies
pip install django
pip install requests
pip install opentelemetry-sdk
pip install opentelemetry-instrumentation-django
pip install opentelemetry-exporter-otlpStep 2: Create a Django project and application
Create an AutoAndManualDemo project:
django-admin startproject AutoAndManualDemoCreate a HelloWorld application in the project:
cd AutoAndManualDemo # Create a HelloWorld application in the project. python manage.py startapp helloworld
Step 3: Add custom spans to your code
Import the OpenTelemetry trace API and create spans around the operations you want to track.
The following Django view example adds two custom spans (hello_world_span and time_span) on top of the spans created automatically by the Django instrumentation plug-in. Modify the helloworld/views.py file:
from django.http import HttpResponse
from opentelemetry import trace
from datetime import datetime
def hello_world_view(request):
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("hello_world_span") as hello_world_span:
result = "Hello World! Current Time =" + str(get_time())
return HttpResponse(result)
def get_time():
now = datetime.now()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("time_span") as time_span:
return now.strftime("%H:%M:%S")Step 4: Modify the urls.py file
Create a
helloworld/urls.pyfile and add the following code:from django.urls import path from . import views urlpatterns = [ path('', views.hello_world_view, name='helloworld') ]Add the URL pattern to the
AutoAndManualDemo/AutoAndManualDemo/urls.pyfile:from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('helloworld/', include('helloworld.urls')), ]
Step 5: Configure the tracer provider
Create an initialization module that sets up the exporter and tracer provider. Add the following code to the OpenTelemetry initialization code in the manual.py file. Import this module early in your application startup (for example, in manage.py or your WSGI/ASGI entry point).
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# To use HTTP instead, uncomment the following line and comment out the gRPC import:
# from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import SERVICE_NAME, HOST_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
resource = Resource(attributes={
SERVICE_NAME: "<your-service-name>",
HOST_NAME: "<host-name>",
})
trace.set_tracer_provider(TracerProvider(resource=resource))
# Export traces over gRPC
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(
endpoint="<endpoint>",
headers="Authentication=<token>", # Required for gRPC only
))
)
# Also print traces to the console (useful for debugging)
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(ConsoleSpanExporter())
)Step 6: Run and verify
python manage.py runserver --noreload- The
--noreloadflag prevents Django from running themanage.mainmethod twice. - If an
ImportError(symbol not found in flat namespace '_CFRelease')error occurs, install the gRPC package:
pip install grpcioSend a request to http://127.0.0.1:8000/helloworld/ and verify trace data in the ARMS console. Follow the steps in the Verify trace reporting section under Automatic instrumentation.
View monitoring data
Log on to the ARMS console.
In the left-side navigation pane, choose Application Monitoring > Applications.
On the Applications page, click the name of your application.
On the application details page, view traces, the application topology, abnormal transactions, slow transactions, and SQL analysis data.
icon appears in the Language column, the application is connected to Application Monitoring. A hyphen (-) indicates a connection to Managed Service for OpenTelemetry.