github.com/gogf/gf/v2@v2.7.4/net/ghttp/ghttp_middleware_tracing.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package ghttp 8 9 import ( 10 "context" 11 "fmt" 12 13 "go.opentelemetry.io/otel" 14 "go.opentelemetry.io/otel/attribute" 15 "go.opentelemetry.io/otel/codes" 16 "go.opentelemetry.io/otel/propagation" 17 "go.opentelemetry.io/otel/trace" 18 19 "github.com/gogf/gf/v2" 20 "github.com/gogf/gf/v2/internal/httputil" 21 "github.com/gogf/gf/v2/net/gtrace" 22 "github.com/gogf/gf/v2/os/gctx" 23 "github.com/gogf/gf/v2/util/gconv" 24 ) 25 26 const ( 27 instrumentName = "github.com/gogf/gf/v2/net/ghttp.Server" 28 tracingEventHttpRequest = "http.request" 29 tracingEventHttpRequestHeaders = "http.request.headers" 30 tracingEventHttpRequestBaggage = "http.request.baggage" 31 tracingEventHttpResponse = "http.response" 32 tracingEventHttpResponseHeaders = "http.response.headers" 33 tracingEventHttpRequestUrl = "http.request.url" 34 tracingMiddlewareHandled gctx.StrKey = `MiddlewareServerTracingHandled` 35 ) 36 37 // internalMiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry. 38 func internalMiddlewareServerTracing(r *Request) { 39 var ( 40 ctx = r.Context() 41 ) 42 // Mark this request is handled by server tracing middleware, 43 // to avoid repeated handling by the same middleware. 44 if ctx.Value(tracingMiddlewareHandled) != nil { 45 r.Middleware.Next() 46 return 47 } 48 49 ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1) 50 var ( 51 span trace.Span 52 tr = otel.GetTracerProvider().Tracer( 53 instrumentName, 54 trace.WithInstrumentationVersion(gf.VERSION), 55 ) 56 ) 57 ctx, span = tr.Start( 58 otel.GetTextMapPropagator().Extract( 59 ctx, 60 propagation.HeaderCarrier(r.Header), 61 ), 62 r.URL.Path, 63 trace.WithSpanKind(trace.SpanKindServer), 64 ) 65 defer span.End() 66 67 span.SetAttributes(gtrace.CommonLabels()...) 68 69 // Inject tracing context. 70 r.SetCtx(ctx) 71 72 // If it is now using a default trace provider, it then does no complex tracing jobs. 73 if gtrace.IsUsingDefaultProvider() { 74 r.Middleware.Next() 75 return 76 } 77 78 span.AddEvent(tracingEventHttpRequest, trace.WithAttributes( 79 attribute.String(tracingEventHttpRequestUrl, r.URL.String()), 80 attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))), 81 attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()), 82 )) 83 84 // Continue executing. 85 r.Middleware.Next() 86 87 // parse after set route as span name 88 if handler := r.GetServeHandler(); handler != nil && handler.Handler.Router != nil { 89 span.SetName(handler.Handler.Router.Uri) 90 } 91 92 // Error logging. 93 if err := r.GetError(); err != nil { 94 span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err)) 95 } 96 97 span.AddEvent(tracingEventHttpResponse, trace.WithAttributes( 98 attribute.String( 99 tracingEventHttpResponseHeaders, 100 gconv.String(httputil.HeaderToMap(r.Response.Header())), 101 ), 102 )) 103 }