Clement Bouthors
Clement Bouthors

Reputation: 53

OpenTelemetry Python - How to instanciate a new span as a child span for a given trace_id

My goal is to perform tracing of the whole process of my application through several component. I am using GCP and Pub/Sub message queue to communicate information between components (developped in Python).

I am currently trying to keep the same root trace between component A and component B by creating a new span as a child span of my root trace.

Here is a small diagram:

Component A            ---> Pub/Sub message       ---> component B
(create the root trace)      (contain information)      (new span for root trace)

I have a given trace_id and span_id of my parent that I can transmit through Pub/Sub but I can't figure out how to declare a new span as a child of this last. All I managed to do is to link a new trace to the parent one but it is not the behavior I am looking for.

Has someone already tried to do something like that ?

Regards,

Upvotes: 5

Views: 9978

Answers (3)

N Hoss
N Hoss

Reputation: 1

from opentelemetry import trace
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.propagate import set_global_textmap, get_global_textmap

    tracer = trace.get_tracer(__name__)
    set_global_textmap(TraceContextTextMapPropagator())

    propagator = get_global_textmap()
    carrier = {}
    with tracer.start_as_current_span("parent_span") as span:
        propagator.inject(carrier=carrier)
        my_method_to_child_span(carrier=carrier, args=args)

#method/.py where your child is

    propagator = get_global_textmap()
    context = propagator.extract(carrier=carrier)
    tracer = trace.get_tracer(__name__)
    
    with tracer.start_as_current_span("child_span", context=context):
        #your logic

Upvotes: 0

Trondh
Trondh

Reputation: 3341

For others coming here, this is what I ended up doing based on @dalalstreetboi3739's suggestions: (I realized that the "trace_id" I got is already a w3c-conformant trace header https://www.w3.org/TR/trace-context/#trace-context-http-headers-format which allowed me to use the TraceContextTextMapPropagator directly ):

data = get_json()
trace_id_str = data['traceid']
carrier = {'traceparent': trace_id_str}

ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
with tracer.start_as_current_span("/api/doit", ctx) as span:
   # do awesome stuff here
   # current span is now a child of the parent "trace_id"
   requests.get("http://what")

Upvotes: 0

Srikanth Chekuri
Srikanth Chekuri

Reputation: 2274

It's called trace context propagation and there are multiple formats such w3c trace context, jaeger, b3 etc... https://github.com/open-telemetry/opentelemetry-specification/blob/b46bcab5fb709381f1fd52096a19541370c7d1b3/specification/context/api-propagators.md#propagators-distribution. You will have to use one of the propagator's inject/extract methods for this. Here is the simple example using W3CTraceContext propagator.

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (BatchSpanProcessor,
                                            ConsoleSpanExporter)
from opentelemetry.trace.propagation.tracecontext import \
    TraceContextTextMapPropagator

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

tracer = trace.get_tracer(__name__)

prop = TraceContextTextMapPropagator()
carrier = {}

# Injecting the context into carrier and send it over

with tracer.start_as_current_span("first-span") as span:
    prop.inject(carrier=carrier)
    print("Carrier after injecting span context", carrier)


# Extracting the remote context from carrier and starting a new span under same trace.

ctx = prop.extract(carrier=carrier)
with tracer.start_as_current_span("next-span", context=ctx):
    pass

Upvotes: 11

Related Questions