github.com/gogf/gf@v1.16.9/net/ghttp/internal/client/client_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 client 8 9 import ( 10 "fmt" 11 "io/ioutil" 12 "net/http" 13 "net/http/httptrace" 14 15 "github.com/gogf/gf" 16 "github.com/gogf/gf/internal/utils" 17 "github.com/gogf/gf/net/ghttp/internal/httputil" 18 "github.com/gogf/gf/net/gtrace" 19 "github.com/gogf/gf/text/gstr" 20 "github.com/gogf/gf/util/gconv" 21 "go.opentelemetry.io/otel" 22 "go.opentelemetry.io/otel/attribute" 23 "go.opentelemetry.io/otel/codes" 24 "go.opentelemetry.io/otel/propagation" 25 "go.opentelemetry.io/otel/trace" 26 ) 27 28 const ( 29 tracingInstrumentName = "github.com/gogf/gf/net/ghttp.Client" 30 tracingAttrHttpAddressRemote = "http.address.remote" 31 tracingAttrHttpAddressLocal = "http.address.local" 32 tracingAttrHttpDnsStart = "http.dns.start" 33 tracingAttrHttpDnsDone = "http.dns.done" 34 tracingAttrHttpConnectStart = "http.connect.start" 35 tracingAttrHttpConnectDone = "http.connect.done" 36 tracingEventHttpRequest = "http.request" 37 tracingEventHttpRequestHeaders = "http.request.headers" 38 tracingEventHttpRequestBaggage = "http.request.baggage" 39 tracingEventHttpRequestBody = "http.request.body" 40 tracingEventHttpResponse = "http.response" 41 tracingEventHttpResponseHeaders = "http.response.headers" 42 tracingEventHttpResponseBody = "http.response.body" 43 ) 44 45 // MiddlewareTracing is a client middleware that enables tracing feature using standards of OpenTelemetry. 46 func MiddlewareTracing(c *Client, r *http.Request) (response *Response, err error) { 47 tr := otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) 48 ctx, span := tr.Start(r.Context(), r.URL.String(), trace.WithSpanKind(trace.SpanKindClient)) 49 defer span.End() 50 51 span.SetAttributes(gtrace.CommonLabels()...) 52 53 // Inject tracing content into http header. 54 otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header)) 55 56 // Continue client handler executing. 57 response, err = c.Next( 58 r.WithContext( 59 httptrace.WithClientTrace( 60 ctx, newClientTrace(ctx, span, r), 61 ), 62 ), 63 ) 64 if err != nil { 65 span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err)) 66 } 67 if response == nil || response.Response == nil { 68 return 69 } 70 71 reqBodyContentBytes, _ := ioutil.ReadAll(response.Body) 72 response.Body = utils.NewReadCloser(reqBodyContentBytes, false) 73 74 span.AddEvent(tracingEventHttpResponse, trace.WithAttributes( 75 attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(response.Header))), 76 attribute.String(tracingEventHttpResponseBody, gstr.StrLimit( 77 string(reqBodyContentBytes), 78 gtrace.MaxContentLogSize(), 79 "...", 80 )), 81 )) 82 return 83 }