Search code examples
goopentracingopen-telemetrydistributed-tracingkrakend

Proper way of extracting tracer from request Headers for opentelemetry


I have krakend apigateway which is using opentracing and sending req headers as X-B3-... for tracing and my service is using opentelemetry.
This is what I'm having right now on jaeger.
enter image description here

enter image description here

I want the service spans to come under the apigateways'.

Workaround I have done:
This is the exact handler for the request using chi router.

func (env *Env) getCommentForBlogRouter(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()

    keys := []string{"X-B3-Traceid", "X-B3-Spanid", "X-B3-Sampled"}
    var carrier propagation.HeaderCarrier = propagation.HeaderCarrier{}
    for _, k := range keys {
        carrier.Set(strings.ToLower(k), r.Header[k][0])
    }

    var propagator propagation.TextMapPropagator = otel.GetTextMapPropagator()
    ctx = propagator.Extract(ctx, carrier)

    // fmt.Println(ctx)
    tr := otel.Tracer("Handler: blog-comments")
    ctx, span := tr.Start(ctx, "handler span")
    defer span.End()

    blogId := r.URL.Query().Get("blog-id")
    span.SetAttributes(attribute.Key("blog-id").String(fmt.Sprint(blogId)))

    var spanDB trace.Span
    ctx, spanDB = tr.Start(ctx, "Select row")

    comments, err := env.comments.GetForBlog(blogId)
    spanDB.End()

    var spanRes trace.Span
    _, spanRes = tr.Start(ctx, "Sending Response")
    defer spanRes.End()

    if err != nil {
        fmt.Println(err)
        SendError(w, http.StatusInternalServerError, "Something went wrong")
        return
    }

    if comments == nil {
        comments = []models.Comment{}
    }
    SendResponse(w, http.StatusOK, map[string]interface{}{
        "data": comments,
    })
}

Solution

  • Ok, I figured out how to make it work. I added this middleware and it will sync the request context with the headers traceID, spanID and traceFlags. After this we are good to create tracer and spans as we want.

    func Tracing(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            traceID, _ := trace.TraceIDFromHex(r.Header["X-B3-Traceid"][0])
            spanID, _ := trace.SpanIDFromHex(r.Header["X-B3-Spanid"][0])
            var traceFlags trace.TraceFlags
            if r.Header["X-B3-Sampled"][0] == "1" {
                traceFlags = trace.FlagsSampled
            }
    
            spanContext := trace.NewSpanContext(trace.SpanContextConfig{
                TraceID:    traceID,
                SpanID:     spanID,
                TraceFlags: traceFlags,
            })
    
            ctx := trace.ContextWithSpanContext(r.Context(), spanContext)
    
            r = r.WithContext(ctx)
            next.ServeHTTP(w, r)
        })
    }