Search code examples
gomicroservicesopentracingdistributed-tracing

SpanContext not found in Extract carrier in microservice


I am trying to implement a Go-based microservice system. I have two service and I try to Inject and Extract span data.

In my first service, I have:

func (apitracer apiTracer) validatemail(res http.ResponseWriter, req *http.Request) {

    validateEmailSpan := apitracer.tracer.StartSpan("Validate Email")

    apitracer.tracer.Inject(
            validateEmailSpan.Context(),
            opentracing.HTTPHeaders,
            opentracing.HTTPHeadersCarrier(req.Header))
        req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
        resp, err := httpClient.Do(req)

In service two :

wireContext, err := opentracing.GlobalTracer().Extract(
        opentracing.HTTPHeaders,
        opentracing.HTTPHeadersCarrier(req.Header))

I get following error :

SpanContext not found in Extract carrier

If I dump log.Println("Form values : ", req.Header.Get("Uber-Trace-Id")), I get proper Uber-Trace-Id value which is same as Service-One.

Request headers are set to application/x-www-form-urlencoded as suggested here

Edit : After @eminlala

Tracer init step.

type apiTracer struct {
    tracer opentracing.Tracer
}

// Tracing function
func startTracing(service string) opentracing.Tracer {

    cfg := config.Configuration{
        Sampler: &config.SamplerConfig{
            Type:  "const",
            Param: 1,
        },
        Reporter: &config.ReporterConfig{
            LogSpans:            true,
            BufferFlushInterval: 1 * time.Second,
        },
    }
    tracer, _, _ := cfg.New(
        service,
        config.Logger(jaeger.StdLogger),
    )
    opentracing.SetGlobalTracer(tracer)

    return tracer
}

Solution

  • Looking at your code I see that you missed to add Injector and Extractor options when creating the tracer. It should look something like this:

    zipkinPropagator := zipkin.NewZipkinB3HTTPHeaderPropagator()
    
    tracer, _, err := cfg.New(
            e.ServiceName, config.Logger(jaeger.StdLogger), config.ZipkinSharedRPCSpan(true),
            config.Injector(opentracing.HTTPHeaders, zipkinPropagator),
            config.Extractor(opentracing.HTTPHeaders, zipkinPropagator))
    
    opentracing.SetGlobalTracer(tracer)
    

    ZipkinPropagator is from github.com/uber/jaeger-client-go/zipkin package.

    You should try ZipkinPropagator because it has less configuration than the plain HTTPHeaderPropagator. ZipkinPropagator receives less parameters, but it's also less flexible. Also, the error you received is from the Extract method is of type opentracing.ErrSpanContextNotFound. Extract method for ZipkinPropagator is less complex as it only check for the TraceID before sending the opentracing.ErrSpanContextNotFound error (when carrier.TraceID()==0).

    You can use the HTTPHeaderPropagator as well, but it has a bit more complex setup, and Extract method checks for more things other than TraceID before sending the opentracing.ErrSpanContextNotFound error (checks for debugID and baggage that is extracted from HeadersConfig).

    EDIT:

    Looking back at your previous question regarding opentracing, if you haven't included Injector and Extractor setup, that might have been the problem why uber-trace-id was not found when extracting the span context in the target service.