Manual instrumentation is the process of adding observability code to your application.
To start tracing, you’ll need to initialize a
First, ensure you have the API and SDK packages:
pip install opentelemetry-api pip install opentelemetry-sdk
Next, initialize a
TracerProvider and set it for your app:
from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchSpanProcessor, ConsoleSpanExporter, ) provider = TracerProvider() processor = BatchSpanProcessor(ConsoleSpanExporter()) provider.add_span_processor(processor) trace.set_tracer_provider(provider) tracer = trace.get_tracer(__name__)
With a call to
get_tracer, you can create spans.
To create a span, you’ll typically want it to be started as the current span.
with tracer.start_as_current_span("span-name") as span: # do some work that 'span' will track # When the 'while' block goes out of scope, 'span' is closed for you
You can also use
start_span to create a span without making it the current
span. This is usually done to track concurrent or asynchronous operations.
Creating nested spans
If you have a distinct sub-operation you’d like to track as a part of another one, you can create spans to represent the relationship:
with tracer.start_as_current_span("parent") as parent: # do some work that 'parent' tracks # Create a nested span to track nested work with tracer.start_as_current_span("child") as child: # do some work that 'child' tracks # the nested span is closed when it's out of scope # This span is also closed when it goes out of scope
When you view spans in a trace visualization tool,
child will be tracked as a
nested span under
Get the current span
Sometimes it’s helpful to access whatever the current span is at a point in time so that you can enrich it with more information.
from opentelemetry import trace current_span = trace.get_current_span() # enrich 'current_span' with some information
Add attributes to a span
Attributes let you attach key/value pairs to a span so it carries more information about the current operation that it’s tracking.
from opentelemetry import trace current_span = trace.get_current_span() current_span.set_attribute("operation.value", 1) current_span.set_attribute("operation.name", "Saying hello!") current_span.set_attribute("operation.other-stuff", [1, 2, 3])
AN event is a human-readable message on a span that represents “something happening” during its lifetime. You can think of it as a primitive log.
from opentelemetry import trace current_span = trace.get_current_span() current_span.add_event("Gonna try it!") # Do the thing current_span.add_event("Did it!")
A span can be created with zero or more span links that causally link it to another span. A link needs a span context to be created.
from opentelemetry import trace ctx = trace.get_current_span().get_span_context() link_from_current = trace.Link(ctx) with tracer.start_as_current_span("new-span", links=[link_from_current]) as new_span: # do something that 'new_span' tracks # The link in 'new_span' casually associated it with the previous one, # but it is not a child span.
Set span status
A status can be set on a span, typically used to specify that a span has not
completed successfully -
StatusCode.ERROR. In rare scenarios, you could
override the Error status with
StatusCode.OK, but don’t set
The status can be set at any time before the span is finished:
from opentelemetry import trace current_span = trace.get_current_span() try: # something that might fail except: current_span.set_status(StatusCode.ERROR)
Record exceptions in spans
It can be a good idea to record exceptions when they happen. It’s recommended to do this in conjunction with setting span status.
from opentelemetry import trace current_span = trace.get_current_span() try: # something that might fail # Consider catching a more specific exception in your code except Exception as ex: current_span.set_status(StatusCode.ERROR) current_span.record_exception(ex)