New Alpha versions of the Python OpenTelemetry API and SDK packages have just been released, and it's time to take them for a test drive! This guide walks through installing the required packages, generating tracing information and propagating context across processes via HTTP.
Setup
In order to get started with OpenTelemetry in Python, we'll need to install the API and SDK packages. This can be done via pip. Note: this requires Python 3.4 or newer.
pip install opentelemetry-api opentelemetry-sdk
Creating a span
In this first example, we'll use the ConsoleSpanExporter
to get us going:
from opentelemetry import trace
from opentelemetry.context import Context
from opentelemetry.sdk.trace import Tracer
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
trace.set_preferred_tracer_implementation(lambda T: Tracer())
tracer = trace.tracer()
# configure the ConsoleSpanExporter as our exporter
span_processor = BatchExportSpanProcessor(ConsoleSpanExporter())
tracer.add_span_processor(span_processor)
with tracer.start_as_current_span('foo'):
with tracer.start_as_current_span('bar'):
with tracer.start_as_current_span('baz'):
print(Context)
span_processor.shutdown()
After running the code, the tracing information will appear in the console:
python console.py
AsyncRuntimeContext({'current_span': Span(name="baz", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0x2202e5e00e02a985, trace_state={}))})
Span(name="baz", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0x2202e5e00e02a985, trace_state={}), kind=SpanKind.INTERNAL, parent=Span(name="bar", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0x10a1a831a5210e6a, trace_state={})), start_time=2019-11-05T23:50:06.569282Z, end_time=2019-11-05T23:50:06.569359Z)
Span(name="bar", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0x10a1a831a5210e6a, trace_state={}), kind=SpanKind.INTERNAL, parent=Span(name="foo", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0xc4beccc7fbb46181, trace_state={})), start_time=2019-11-05T23:50:06.569255Z, end_time=2019-11-05T23:50:06.569482Z)
Span(name="foo", context=SpanContext(trace_id=0xddf0ac0d009a33320781ccac56018ead, span_id=0xc4beccc7fbb46181, trace_state={}), kind=SpanKind.INTERNAL, parent=None, start_time=2019-11-05T23:50:06.569221Z, end_time=2019-11-05T23:50:06.569561Z)
Console output is a great start. Now, let's try sending our traces into JaegerJaeger. The following command will launch the "handy in dev" but "don't use it in PROD" all-in-one Jaeger Docker container:
docker run -d -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one:latest
You should be able to visit http://localhost:16686http://localhost:16686:
pip install opentelemetry-ext-jaeger
With those in place, we can now configure the JaegerSpanExporter
to send traces to the container we just launched.
from opentelemetry.ext import jaeger
...
# create a JaegerSpanExporter
jaeger_exporter = jaeger.JaegerSpanExporter(
service_name="getting-started-jaeger", agent_host_name="localhost", agent_port=6831,
)
span_processor = BatchExportSpanProcessor(jaeger_exporter)
...
Navigating through the Jaeger interface using a browser http://localhost:16686http://localhost:16686, we should now be able to find the trace that was just created.
Propagating the Context
The next example will walk through making a request from a client to a server, which allows us to test context propagation across process boundaries. Let's start with the dependencies:
pip install flask opentelemetry-ext-wsgi opentelemetry-ext-http-requests
For the server, we'll use the OpenTelemetryMiddlewareOpenTelemetryMiddleware.
import flask
import requests
from opentelemetry import trace
from opentelemetry.ext import http_requests
from opentelemetry.ext.wsgi import OpenTelemetryMiddleware
...
http_requests.enable(tracer)
app = flask.Flask(__name__)
app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)
@app.route("/")
def hello():
with tracer.start_as_current_span("parent"):
requests.get("https://www.wikipedia.org/wiki/Rabbit")
return "hello"
if __name__ == "__main__":
app.run(debug=True)
span_processor.shutdown()
The client code will make a request to the server using the Requests module, which we'll instrument via the http_request
OpenTelemetry extension.
import requests
from opentelemetry import trace
from opentelemetry.ext import http_requests
...
http_requests.enable(tracer)
response = requests.get(url="http://127.0.0.1:5000/")
span_processor.shutdown()
That's it! You're now ready to instrument your Python code with OpenTelemetry! If you're interested in contributing but aren't sure how to, be sure to check out the recent blog post on How to Start ContributingHow to Start Contributing repo if you'd like to get involved!
Interested in joining our team? See our open positions herehere.
Explore more articles

From Day 0 to Day 2: Reducing the anxiety of scaling up cloud-native deployments
Jason English | Mar 7, 2023The global cloud-native development community is facing a reckoning. There are too many tools, too much telemetry data, and not enough skilled people to make sense of it all. See how you can.
Learn moreLearn more
OpenTelemetry Collector in Kubernetes: Get started with autoscaling
Moh Osman | Jan 6, 2023Learn how to leverage a Horizontal Pod Autoscaler alongside the OpenTelemetry Collector in Kubernetes. This will enable a cluster to handle varying telemetry workloads as the collector pool aligns to demand.
Learn moreLearn more
Observability-Landscape-as-Code in Practice
Adriana Villela, Ana Margarita Medina | Oct 25, 2022Learn how to put Observability-Landscape-as-Code in this hands-on tutorial. In it, you'll use Terraform to create a Kubernetes cluster, configure and deploy the OTel Demo App to send Traces and Metrics to Lightstep, and create dashboards in Lightstep.
Learn moreLearn moreLightstep sounds like a lovely idea
Monitoring and observability for the world’s most reliable systems