krakend / krakend-ce

KrakenD Community Edition: High-performance, stateless, declarative, API Gateway written in Go.
https://www.krakend.io
Apache License 2.0
1.94k stars 453 forks source link

Opentelemetry tracing context in custom plugins #859

Closed tsemczyszyn closed 6 months ago

tsemczyszyn commented 6 months ago

I have a custom plugin (HTTP Server) that calls out to another service to do some checks before passing the request. With the addition of opentelemetry tracing in 2.6 it would be nice if I could propagate that context into the plugin so that the calls to the external service can be included in the trace. Is this possible to do now and if so do you have an example?

rjfonseca commented 6 months ago

Hi there! I've just tested that today on my code and it is indeed working. (I'm no expert on krakend or otel).

The context in the handler in the plugin has a span, the problem I had was with the Tracer. KrakenD is not initializing a global tracer and its tracer is private (I didn't find a place to get it). You have to get the provider from the current span (or initialize a global tracer).

I did what the official HTTP handler does and created a helper package to handle that:

package tracer

import (
    "context"

    "go.opentelemetry.io/otel/trace"
    "go.opentelemetry.io/otel/trace/noop"
)

const ScopeName = "your-scope"

func FromContext(ctx context.Context) trace.Tracer {
    if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
        return span.TracerProvider().Tracer(ScopeName)
    }

    return noop.NewTracerProvider().Tracer(ScopeName)
}

and then:

ctx, span := tracer.FromContext(ctx).Start(ctx, "something")
defer span.End()

The http client instrumentation was straightforward:

client.Transport = otelhttp.NewTransport(client.Transport)

I hope this help. I'm also interested if anyone know other ways to make it work.

alombarte commented 6 months ago

Thanks @rjfonseca for the example. I am closing the issue as you answered the question.