If you have not read the setup instructions for automatic instrumentation, start with the Python Setup Instructions
If you aren’t using supported library instrumentation (see library compatibility), you may want to manually instrument your code.
You may also want to extend the functionality of the ddtrace library or gain finer control over instrumenting your application. Several techniques are provided by the library to accomplish this.
The ddtrace library creates spans automatically with ddtrace-run for many libraries and frameworks. However, you may want to gain visibility into your own code and this is achieved by using spans.
Within your web request (for example, make_sandwich_request), you may perform several operations, like get_ingredients() and assemble_sandwich(), which are useful to measure.
ddtrace provides a decorator tracer.wrap() that can be used to decorate the functions of interest. This is useful if you would like to trace the function regardless of where it is being called from.
fromddtraceimporttracer@tracer.wrap(service="my-sandwich-making-svc",resource="resource_name")defget_ingredients():# go to the pantry# go to the fridge# maybe go to the storereturn# You can provide more information to customize the span@tracer.wrap("assemble_sandwich",service="my-sandwich-making-svc",resource="resource_name")defassemble_sandwich(ingredients):return
To trace an arbitrary block of code, use the ddtrace.Span context manager as below, or view the advanced usage documentation.
fromddtraceimporttracerdefmake_sandwich_request(request):# Capture both operations in a spanwithtracer.trace("sandwich.make"):ingredients=get_ingredients()sandwich=assemble_sandwich(ingredients)defmake_sandwich_request(request):# Capture both operations in a spanwithtracer.trace("sandwich.create",resource="resource_name")asouter_span:withtracer.trace("get_ingredients",resource="resource_name")asspan:ingredients=get_ingredients()withtracer.trace("assemble_sandwich",resource="resource_name")asspan:sandwich=assemble_sandwich(ingredients)
If the decorator and context manager methods are still not enough to satisfy your tracing needs, a manual API is provided which allows you to start and finish spans however you may require:
defmake_sandwich_request(request):span=tracer.trace("sandwich.create",resource="resource_name")ingredients=get_ingredients()sandwich=assemble_sandwich(ingredients)span.finish()# remember to finish the span
The built-in instrumentation and your own custom instrumentation create spans around meaningful operations. You can access the active span in order to include meaningful data.
fromddtraceimporttracerdefmake_sandwich_request(request):# Capture both operations in a spanwithtracer.trace("sandwich.make")asmy_span:ingredients=get_ingredients()sandwich=assemble_sandwich(ingredients)
defget_ingredients():# Get the active spanspan=tracer.current_span()# this span is my_span from make_sandwich_request above
defassemble_sandwich(ingredients):withtracer.trace("another.operation")asanother_span:# Get the active root spanspan=tracer.current_root_span()# this span is my_span from make_sandwich_request above
Tags can be globally set on the tracer. These tags are be applied to every span that is created.
fromddtraceimporttracerfrommyappimport__version__# This will be applied to every spantracer.set_tags({"version":__version__,"<TAG_KEY_2>":"<TAG_VALUE_2>"})
Exception information is captured and attached to a span if there is one active when the exception is raised.
fromddtraceimporttracerwithtracer.trace("throws.an.error")asspan:raiseException("Oops!")# `span` will be flagged as erroneous and have# the stack trace and exception message attached as tags
Flagging a span as erroneous can also be done manually:
In the event you want to flag the local root span with the error raised:
importosfromddtraceimporttracertry:raiseTypeErrorexceptTypeErrorase:root_span=tracer.current_root_span()(exc_type,exc_val,exc_tb)=sys.exc_info()# this sets the error type, marks the span as an error, and adds the tracebackroot_span.set_exc_info(exc_type,exc_val,exc_tb)
You can configure the propagation of context for distributed traces by injecting and extracting headers. Read Trace Context Propagation for information.
The ddtrace-api Python package is in Preview and may not include all the API calls you need. If you need more complete functionality, use the API as described in the previous sections.
The following steps are only necessary if you want to experiment with the in Preview ddtrace-api package.
The ddtrace-api package provides a stable public API for Datadog APM’s custom Python instrumentation. This package implements only the API interface, not the underlying functionality that creates and sends spans to Datadog.
This separation between interface (ddtrace-api) and implementation (ddtrace) offers several benefits:
You can rely on an API that changes less frequently and more predictably for your custom instrumentation
If you only use automatic instrumentation, you can ignore API changes entirely
If you implement both single-step and custom instrumentation, you avoid depending on multiple copies of the ddtrace package
To use ddtrace-api:
Install both the ddtrace and ddtrace-api libraries:
pipinstall'ddtrace>=3.1'ddtrace-api
Instrument your Python application using ddtrace-run by prefixing your Python entry-point command:
ddtrace-run python app.py
After this is set up, you can write custom instrumentation exactly like the examples in the previous sections, but you import from ddtrace_api instead of ddtrace.
For example:
fromddtrace_apiimporttracer@tracer.wrap(service="my-sandwich-making-svc",resource="resource_name")defget_ingredients():# go to the pantry# go to the fridge# maybe go to the storereturn
See that package’s API definition for the full list of supported API calls.