123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package gclient
- import (
- "context"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/http/httptrace"
- "go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
- "go.opentelemetry.io/otel/propagation"
- "go.opentelemetry.io/otel/trace"
- "github.com/gogf/gf/v2"
- "github.com/gogf/gf/v2/internal/httputil"
- "github.com/gogf/gf/v2/internal/utils"
- "github.com/gogf/gf/v2/net/gtrace"
- "github.com/gogf/gf/v2/os/gctx"
- "github.com/gogf/gf/v2/text/gstr"
- "github.com/gogf/gf/v2/util/gconv"
- )
- const (
- tracingInstrumentName = "github.com/gogf/gf/v2/net/gclient.Client"
- tracingAttrHttpAddressRemote = "http.address.remote"
- tracingAttrHttpAddressLocal = "http.address.local"
- tracingAttrHttpDnsStart = "http.dns.start"
- tracingAttrHttpDnsDone = "http.dns.done"
- tracingAttrHttpConnectStart = "http.connect.start"
- tracingAttrHttpConnectDone = "http.connect.done"
- tracingEventHttpRequest = "http.request"
- tracingEventHttpRequestHeaders = "http.request.headers"
- tracingEventHttpRequestBaggage = "http.request.baggage"
- tracingEventHttpRequestBody = "http.request.body"
- tracingEventHttpResponse = "http.response"
- tracingEventHttpResponseHeaders = "http.response.headers"
- tracingEventHttpResponseBody = "http.response.body"
- tracingMiddlewareHandled gctx.StrKey = `MiddlewareClientTracingHandled`
- )
- // internalMiddlewareTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
- func internalMiddlewareTracing(c *Client, r *http.Request) (response *Response, err error) {
- var ctx = r.Context()
- // Mark this request is handled by server tracing middleware,
- // to avoid repeated handling by the same middleware.
- if ctx.Value(tracingMiddlewareHandled) != nil {
- return c.Next(r)
- }
- ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
- tr := otel.GetTracerProvider().Tracer(
- tracingInstrumentName,
- trace.WithInstrumentationVersion(gf.VERSION),
- )
- ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindClient))
- defer span.End()
- span.SetAttributes(gtrace.CommonLabels()...)
- // Inject tracing content into http header.
- otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))
- // If it is now using default trace provider, it then does no complex tracing jobs.
- if gtrace.IsUsingDefaultProvider() {
- response, err = c.Next(r)
- return
- }
- // Continue client handler executing.
- response, err = c.Next(
- r.WithContext(
- httptrace.WithClientTrace(
- ctx, newClientTrace(ctx, span, r),
- ),
- ),
- )
- if err != nil {
- span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
- }
- if response == nil || response.Response == nil {
- return
- }
- reqBodyContentBytes, _ := ioutil.ReadAll(response.Body)
- response.Body = utils.NewReadCloser(reqBodyContentBytes, false)
- span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
- attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(response.Header))),
- attribute.String(tracingEventHttpResponseBody, gstr.StrLimit(
- string(reqBodyContentBytes),
- gtrace.MaxContentLogSize(),
- "...",
- )),
- ))
- return
- }
|