Package: opentracing
This library is a Python platform API for OpenTracing.Required ReadingIn order to understand the Python platform API, one must first be familiar with
theOpenTracing projectandterminologymore
specifically.StatusIn the current version,opentracing-pythonprovides only the API and a
basic no-op implementation that can be used by instrumentation libraries to
collect and propagate distributed tracing context.Future versions will include a reference implementation utilizing an
abstract Recorder interface, as well as aZipkin-compatible Tracer.UsageThe work of instrumentation libraries generally consists of three steps:When a service receives a new request (over HTTP or some other protocol),
it uses OpenTracing’s inject/extract API to continue an active trace, creating a
Span object in the process. If the request does not contain an active trace,
the service starts a new trace and a newrootSpan.The service needs to store the current Span in some request-local storage,
(calledSpanactivation) where it can be retrieved from when a child Span must
be created, e.g. in case of the service making an RPC to another service.When making outbound calls to another service, the current Span must be
retrieved from request-local storage, a child span must be created (e.g., by
using thestart_child_span()helper), and that child span must be embedded
into the outbound request (e.g., using HTTP headers) via OpenTracing’s
inject/extract API.Below are the code examples for the previously mentioned steps. Implementation
of request-local storage needed for step 2 is specific to the service and/or frameworks /
instrumentation libraries it is using, exposed as aScopeManagerchild contained
asTracer.scope_manager. See details below.Inbound requestSomewhere in your server’s request handler code:defhandle_request(request):span=before_request(request,opentracing.global_tracer())# store span in some request-local storage using Tracer.scope_manager,# using the returned `Scope` as Context Manager to ensure# `Span` will be cleared and (in this case) `Span.finish()` be called.withtracer.scope_manager.activate(span,True)asscope:# actual business logichandle_request_for_real(request)defbefore_request(request,tracer):span_context=tracer.extract(format=Format.HTTP_HEADERS,carrier=request.headers,)span=tracer.start_span(operation_name=request.operation,child_of=span_context)span.set_tag('http.url',request.full_url)remote_ip=request.remote_ipifremote_ip:span.set_tag(tags.PEER_HOST_IPV4,remote_ip)caller_name=request.caller_nameifcaller_name:span.set_tag(tags.PEER_SERVICE,caller_name)remote_port=request.remote_portifremote_port:span.set_tag(tags.PEER_PORT,remote_port)returnspanOutbound requestSomewhere in your service that’s about to make an outgoing call:fromopentracingimporttagsfromopentracing.propagationimportFormatfromopentracing_instrumentationimportrequest_context# create and serialize a child span and use it as context managerwithbefore_http_request(request=out_request,current_span_extractor=request_context.get_current_span):# actual callreturnurllib2.urlopen(request)defbefore_http_request(request,current_span_extractor):op=request.operationparent_span=current_span_extractor()outbound_span=opentracing.global_tracer().start_span(operation_name=op,child_of=parent_span)outbound_span.set_tag('http.url',request.full_url)service_name=request.service_namehost,port=request.host_portifservice_name:outbound_span.set_tag(tags.PEER_SERVICE,service_name)ifhost:outbound_span.set_tag(tags.PEER_HOST_IPV4,host)ifport:outbound_span.set_tag(tags.PEER_PORT,port)http_header_carrier={}opentracing.global_tracer().inject(span_context=outbound_span,format=Format.HTTP_HEADERS,carrier=http_header_carrier)forkey,valueinhttp_header_carrier.iteritems():request.add_header(key,value)returnoutbound_spanScope and within-process propagationFor getting/setting the current activeSpanin the used request-local storage,
OpenTracing requires that everyTracercontains aScopeManagerthat grants
access to the activeSpanthrough aScope. AnySpanmay be transferred to
another task or thread, but notScope.# Access to the active span is straightforward.scope=tracer.scope_manager.active()ifscopeisnotNone:scope.span.set_tag('...','...')The common case starts aScopethat’s automatically registered for intra-process
propagation viaScopeManager.Note thatstart_active_span('...')automatically finishes the span onScope.close()(start_active_span('...',finish_on_close=False)does not finish it, in contrast).# Manual activation of the Span.span=tracer.start_span(operation_name='someWork')withtracer.scope_manager.activate(span,True)asscope:# Do things.# Automatic activation of the Span.# finish_on_close is a required parameter.withtracer.start_active_span('someWork',finish_on_close=True)asscope:# Do things.# Handling done through a try construct:span=tracer.start_span(operation_name='someWork')scope=tracer.scope_manager.activate(span,True)try:# Do things.exceptExceptionase:span.set_tag('error','...')finally:scope.close()If there is a Scope, it will act as the parent to any newly started Spanunless
the programmer passesignore_active_span=Trueatstart_span()/start_active_span()time or specified parent context explicitly:scope=tracer.start_active_span('someWork',ignore_active_span=True)Each service/framework ought to provide a specificScopeManagerimplementation
that relies on their own request-local storage (thread-local storage, or coroutine-based storage
for asynchronous frameworks, for example).Scope managersThis project includes a set ofScopeManagerimplementations under theopentracing.scope_managerssubmodule, which can be imported on demand:fromopentracing.scope_managersimportThreadLocalScopeManagerThere exist implementations forthread-local(the default instance of the submoduleopentracing.scope_managers),gevent,Tornado,asyncioandcontextvars:fromopentracing.scope_managers.geventimportGeventScopeManager# requires geventfromopentracing.scope_managers.tornadoimportTornadoScopeManager# requires tornado<6fromopentracing.scope_managers.asyncioimportAsyncioScopeManager# fits for old asyncio applications, requires Python 3.4 or newer.fromopentracing.scope_managers.contextvarsimportContextVarsScopeManager# for asyncio applications, requires Python 3.7 or newer.Notethat for asyncio applications it’s preferable to useContextVarsScopeManagerinstead ofAsyncioScopeManagerbecause of automatic parent span propagation to children coroutines, tasks or scheduled callbacks.DevelopmentTestsvirtualenvenv../env/bin/activatemakebootstrapmaketestYou can usetoxto run tests as well.toxTestbed suiteA testbed suite designed to test API changes and experimental features is included under thetestbeddirectory. For more information, see theTestbed README.Instrumentation TestsThis project has a working design of interfaces for the OpenTracing API. There is a MockTracer to
facilitate unit-testing of OpenTracing Python instrumentation.fromopentracing.mocktracerimportMockTracertracer=MockTracer()withtracer.start_span('someWork')asspan:passspans=tracer.finished_spans()someWorkSpan=spans[0]Documentationvirtualenvenv../env/bin/activatemakebootstrapmakedocsThe documentation is written todocs/_build/html.LICENSEApache 2.0 License.ReleasesBefore new release, add a summary of changes since last version to CHANGELOG.rstpipinstallzest.releaser[recommended]prereleasereleasegitpushoriginmaster--follow-tagspythonsetup.pysdistupload-rpypiupload_docs-rpypipostreleasegitpush