Spring Boot Jaeger create new Span for given TraceId

Viewed 3226

so I'm playing aroung with Jaeger and OpenTracing to trace the requests between my Spring Boot microservices. I have setup all necessary configurations and added the dependency:

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-spring-jaeger-web-starter</artifactId>
    <version>2.0.3</version>
</dependency>

So far all works fine. I see all the traces and spans in my Jaeger UI, no problem.

But now I have the challenge to add new spans to a specific trace, that is already finished. Think of it like this. A client calls one of the services and the tracing starts. After the work is done, I see the trace in my Jaeger UI. But now the invoking clients wants to add some additional tracing data to the specific trace. Like tracing information from other service, that are not within the scope of my microservices. I've added a filter so I can extract the trace id and send it to the client. Now the client does a request containing the additional trace information and the trace id. These informationa should then be added as an additional span in the already finished trace.

Now to my question. Is there a way to create a span and add it to a trace with only having the trace id as a String?

I've tried Zipkin and I could just do:

Span span = new SpanBuilder()
                .name(someName)
                .traceId(traceId)
                .parentId(traceId)
                .id(someId)
                .kind(Kind.CLIENT)
                .build()

That span could then be added by doing a POST request to my zipkin server on port 9411 which did the magic of adding this span to the trace with the given id.

Using OpenTracing I can do:

Span span = tracer.buildSpan(someName)
                .asChildOf(**traceSpan**)
                .withStartTimestamp(someTime)
                .ignoreActiveSpan()
                .start();

Unfortunately this approach needs the trace in form of a span to create the new span as a child of that trace. Given the fact that I can only provide the trace id, I don't know how to get the needed span of that trace. Do I really need to make a call to my the Jaeger query to get the trace span needed or is there another approach I haven't been thinking of?

Would really like to get some help on this.

Cheers!

2 Answers

You need to send the trace-id from one server into another. I'll list here one way to implement a code that actually works assuming you already has an original span created at service 1 and a tracer instance (JaegerTracer) created.

First, you need to get the span-id from the span at your service1:

JaegerSpan span = tracer.buildSpan("service1")
String spanId = span.context().toTraceId()

Now, you can propagate this string (spanId) to your other services. Ex: If you are using http/post or kafka, there are some protocols to follow ex: w3c . But in an root way

import io.jaegertracing.internal.JaegerSpan;
import io.jaegertracing.internal.JaegerSpanContext;
import io.jaegertracing.internal.propagation.TextMapCodec;
import io.jaegertracing.internal.propagation.TextMapCodec.Builder;
//...
// assuming you've extracted your trace-id as string from your messaging system
// kafka header, http header, grpc metadata, wherever...
TextMap carrier = new TextMapAdapter(Map.of("uber-trace-id", traceId));
TextMapCodec codec = New Builder().build();

// I guess this line answer your question (get spanContext from trace-id)
JaegerSpanContext sc = codec.extract(carrier);
JaegerSpan sp = tracer.buildSpan("service2").asChildOf(sc).start();

like what @Totalys says , but need some modification the value associate with the key "uber-trace-id" should be the context().toString() instead of context().toTraceId

Related