github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf. 6 7 package ghttp 8 9 import ( 10 "context" 11 "fmt" 12 "io" 13 14 "go.opentelemetry.io/otel" 15 "go.opentelemetry.io/otel/attribute" 16 "go.opentelemetry.io/otel/codes" 17 "go.opentelemetry.io/otel/propagation" 18 "go.opentelemetry.io/otel/trace" 19 20 "github.com/wangyougui/gf/v2" 21 "github.com/wangyougui/gf/v2/errors/gerror" 22 "github.com/wangyougui/gf/v2/internal/httputil" 23 "github.com/wangyougui/gf/v2/internal/utils" 24 "github.com/wangyougui/gf/v2/net/gtrace" 25 "github.com/wangyougui/gf/v2/os/gctx" 26 "github.com/wangyougui/gf/v2/util/gconv" 27 ) 28 29 const ( 30 tracingInstrumentName = "github.com/wangyougui/gf/v2/net/ghttp.Server" 31 tracingEventHttpRequest = "http.request" 32 tracingEventHttpRequestHeaders = "http.request.headers" 33 tracingEventHttpRequestBaggage = "http.request.baggage" 34 tracingEventHttpRequestBody = "http.request.body" 35 tracingEventHttpResponse = "http.response" 36 tracingEventHttpResponseHeaders = "http.response.headers" 37 tracingEventHttpResponseBody = "http.response.body" 38 tracingEventHttpRequestUrl = "http.request.url" 39 tracingMiddlewareHandled gctx.StrKey = `MiddlewareServerTracingHandled` 40 ) 41 42 // internalMiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry. 43 func internalMiddlewareServerTracing(r *Request) { 44 var ( 45 ctx = r.Context() 46 ) 47 // Mark this request is handled by server tracing middleware, 48 // to avoid repeated handling by the same middleware. 49 if ctx.Value(tracingMiddlewareHandled) != nil { 50 r.Middleware.Next() 51 return 52 } 53 54 ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1) 55 var ( 56 span trace.Span 57 tr = otel.GetTracerProvider().Tracer( 58 tracingInstrumentName, 59 trace.WithInstrumentationVersion(gf.VERSION), 60 ) 61 ) 62 ctx, span = tr.Start( 63 otel.GetTextMapPropagator().Extract( 64 ctx, 65 propagation.HeaderCarrier(r.Header), 66 ), 67 r.URL.Path, 68 trace.WithSpanKind(trace.SpanKindServer), 69 ) 70 defer span.End() 71 72 span.SetAttributes(gtrace.CommonLabels()...) 73 74 // Inject tracing context. 75 r.SetCtx(ctx) 76 77 // If it is now using a default trace provider, it then does no complex tracing jobs. 78 if gtrace.IsUsingDefaultProvider() { 79 r.Middleware.Next() 80 return 81 } 82 83 // Request content logging. 84 reqBodyContentBytes, err := io.ReadAll(r.Body) 85 if err != nil { 86 r.SetError(gerror.Wrap(err, `read request body failed`)) 87 span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err)) 88 return 89 } 90 r.Body = utils.NewReadCloser(reqBodyContentBytes, false) 91 reqBodyContent, err := gtrace.SafeContentForHttp(reqBodyContentBytes, r.Header) 92 if err != nil { 93 span.SetStatus(codes.Error, fmt.Sprintf(`converting safe content failed: %s`, err.Error())) 94 } 95 96 span.AddEvent(tracingEventHttpRequest, trace.WithAttributes( 97 attribute.String(tracingEventHttpRequestUrl, r.URL.String()), 98 attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))), 99 attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()), 100 attribute.String(tracingEventHttpRequestBody, reqBodyContent), 101 )) 102 103 // Continue executing. 104 r.Middleware.Next() 105 106 // parse after set route as span name 107 if r.Router.Uri != defaultMiddlewarePattern || r.Router.RegNames != nil { 108 span.SetName(r.Router.Uri) 109 } 110 111 // Error logging. 112 if err = r.GetError(); err != nil { 113 span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err)) 114 } 115 116 // Response content logging. 117 resBodyContent, err := gtrace.SafeContentForHttp(r.Response.Buffer(), r.Response.Header()) 118 if err != nil { 119 span.SetStatus(codes.Error, fmt.Sprintf(`converting safe content failed: %s`, err.Error())) 120 } 121 122 span.AddEvent(tracingEventHttpResponse, trace.WithAttributes( 123 attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))), 124 attribute.String(tracingEventHttpResponseBody, resBodyContent), 125 )) 126 }