github.com/avenga/couper@v1.12.2/handler/middleware/trace.go (about) 1 package middleware 2 3 import ( 4 "net/http" 5 6 "go.opentelemetry.io/otel" 7 "go.opentelemetry.io/otel/attribute" 8 semconv "go.opentelemetry.io/otel/semconv/v1.12.0" 9 "go.opentelemetry.io/otel/trace" 10 11 "github.com/avenga/couper/config/request" 12 "github.com/avenga/couper/logging" 13 "github.com/avenga/couper/telemetry/instrumentation" 14 ) 15 16 type TraceHandler struct { 17 handler http.Handler 18 } 19 20 func NewTraceHandler() Next { 21 return func(handler http.Handler) *NextHandler { 22 return NewHandler(&TraceHandler{ 23 handler: handler, 24 }, handler) 25 } 26 } 27 28 func (th *TraceHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { 29 spanName := req.URL.EscapedPath() 30 opts := []trace.SpanStartOption{ 31 trace.WithAttributes(semconv.NetAttributesFromHTTPRequest("tcp", req)...), 32 trace.WithAttributes(semconv.EndUserAttributesFromHTTPRequest(req)...), 33 trace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest("couper", spanName, req)...), 34 trace.WithSpanKind(trace.SpanKindServer), 35 trace.WithAttributes(attribute.String("couper.uid", req.Context().Value(request.UID).(string))), 36 } 37 38 tracer := otel.GetTracerProvider().Tracer(instrumentation.Name) 39 ctx, span := tracer.Start(req.Context(), spanName, opts...) 40 defer span.End() 41 42 *req = *req.WithContext(ctx) 43 th.handler.ServeHTTP(rw, req) 44 45 if rsw, ok := rw.(logging.RecorderInfo); ok { 46 attrs := semconv.HTTPAttributesFromHTTPStatusCode(rsw.StatusCode()) 47 spanStatus, spanMessage := semconv.SpanStatusFromHTTPStatusCode(rsw.StatusCode()) 48 span.SetAttributes(attrs...) 49 span.SetStatus(spanStatus, spanMessage) 50 } 51 }