Manually setting a trace-id for 2 separate traces, results in no root span

113 Views Asked by At

I'm currently writing a python program that is generating some synthetic trace to replicate what we will have later in our distributed environment.

The code generates the correct 2 traces, using the same traceID so they are both visible in a single trace view. I am using Tempo + Grafana for this.

However, it is missing what is called a "root span" and I have no idea how to add this.

This is what I have worked on so far:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace import SpanContext, TraceFlags, NonRecordingSpan, set_span_in_context
import random

def generate_hex_string(length):
    return ''.join(random.choice('0123456789abcdef') for _ in range(length))

# Function to create a tracer provider for a specific service
def create_tracer_provider(service_name):
    tracer_provider = TracerProvider(resource=Resource.create({"service.name": service_name}))
    otlp_exporter = OTLPSpanExporter(
        endpoint="localhost:3100",
        insecure=True,
        headers={"authorization": "Basic =="}
    )
    span_processor = SimpleSpanProcessor(otlp_exporter)
    tracer_provider.add_span_processor(span_processor)
    return tracer_provider

# Create tracer providers for different services
service1_tracer_provider = create_tracer_provider("mobile_bank")
service2_tracer_provider = create_tracer_provider("balance_service")

# Manually create a TraceId and SpanId as integers
trace_id = int(generate_hex_string(32), 16)
span_id = int(generate_hex_string(16), 16)

# Create a valid SpanContext with the artificial TraceId and SpanId
span_context = SpanContext(
    trace_id=trace_id,
    span_id=span_id,
    is_remote=True,
    trace_flags=TraceFlags(TraceFlags.SAMPLED)
)

# Create a non-recording span with this SpanContext
non_recording_span = NonRecordingSpan(span_context)

# Set the context with this span
context = set_span_in_context(non_recording_span)

# Generate a root span for "e-commerce" using the context

# Generate a span for Service 1 using the context
with service1_tracer_provider.get_tracer("mobile-bank-app").start_as_current_span("open", context=context) as span1:
    span1.set_attribute("attribute1", "value1")

    # Generate a subspan for Service 1
    with service1_tracer_provider.get_tracer("mobile-bank-app").start_as_current_span("check_balance") as subspan1:
        subspan1.set_attribute("subspan_attribute1", "subspan_value1")

# Generate a span for Service 2 using the context
with service2_tracer_provider.get_tracer("balanceapi").start_as_current_span("get_balance", context=context) as span2:
    span2.set_attribute("attribute2", "value2")

    # Generate a subspan for Service 2
    with service2_tracer_provider.get_tracer("balanceapi").start_as_current_span("redis-request") as subspan2:
        subspan2.set_attribute("subspan_attribute2", "subspan_value2")

# Wait for traces to be exported
import time
time.sleep(2)

When I try to add a parent span to my existing code without a context to simulate a root span, it ends up in its own separate trace.

If I remove the context completely and just send in 1 trace without setting the traceID, the root span shows up.

0

There are 0 best solutions below