github.com/gogf/gf/v2@v2.7.4/net/gclient/gclient_observability.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 gclient
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"net/http"
    13  	"net/http/httptrace"
    14  
    15  	"go.opentelemetry.io/otel"
    16  	"go.opentelemetry.io/otel/attribute"
    17  	"go.opentelemetry.io/otel/codes"
    18  	"go.opentelemetry.io/otel/propagation"
    19  	"go.opentelemetry.io/otel/trace"
    20  
    21  	"github.com/gogf/gf/v2"
    22  	"github.com/gogf/gf/v2/internal/httputil"
    23  	"github.com/gogf/gf/v2/net/gtrace"
    24  	"github.com/gogf/gf/v2/os/gctx"
    25  	"github.com/gogf/gf/v2/os/gmetric"
    26  	"github.com/gogf/gf/v2/util/gconv"
    27  )
    28  
    29  const (
    30  	instrumentName                              = "github.com/gogf/gf/v2/net/gclient.Client"
    31  	tracingAttrHttpAddressRemote                = "http.address.remote"
    32  	tracingAttrHttpAddressLocal                 = "http.address.local"
    33  	tracingAttrHttpDnsStart                     = "http.dns.start"
    34  	tracingAttrHttpDnsDone                      = "http.dns.done"
    35  	tracingAttrHttpConnectStart                 = "http.connect.start"
    36  	tracingAttrHttpConnectDone                  = "http.connect.done"
    37  	tracingEventHttpRequest                     = "http.request"
    38  	tracingEventHttpRequestHeaders              = "http.request.headers"
    39  	tracingEventHttpRequestBaggage              = "http.request.baggage"
    40  	tracingEventHttpResponse                    = "http.response"
    41  	tracingEventHttpResponseHeaders             = "http.response.headers"
    42  	tracingMiddlewareHandled        gctx.StrKey = `MiddlewareClientTracingHandled`
    43  )
    44  
    45  // internalMiddlewareObservability is a client middleware that enables observability feature.
    46  func internalMiddlewareObservability(c *Client, r *http.Request) (response *Response, err error) {
    47  	var ctx = r.Context()
    48  	// Mark this request is handled by server tracing middleware,
    49  	// to avoid repeated handling by the same middleware.
    50  	if ctx.Value(tracingMiddlewareHandled) != nil {
    51  		return c.Next(r)
    52  	}
    53  
    54  	ctx = context.WithValue(ctx, tracingMiddlewareHandled, 1)
    55  	tr := otel.GetTracerProvider().Tracer(
    56  		instrumentName,
    57  		trace.WithInstrumentationVersion(gf.VERSION),
    58  	)
    59  	ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindClient))
    60  	defer span.End()
    61  
    62  	span.SetAttributes(gtrace.CommonLabels()...)
    63  
    64  	// Inject tracing content into http header.
    65  	otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))
    66  
    67  	// Inject ClientTrace into context for http request.
    68  	var (
    69  		httpClientTracer       *httptrace.ClientTrace
    70  		baseClientTracer       = newClientTracerNoop()
    71  		isUsingDefaultProvider = gtrace.IsUsingDefaultProvider()
    72  	)
    73  	// Tracing.
    74  	if !isUsingDefaultProvider {
    75  		baseClientTracer = newClientTracerTracing(ctx, span, r)
    76  	}
    77  	// Metrics.
    78  	if gmetric.IsEnabled() {
    79  		baseClientTracer = newClientTracerMetrics(r, baseClientTracer)
    80  	}
    81  	httpClientTracer = newClientTracer(baseClientTracer)
    82  	r = r.WithContext(
    83  		httptrace.WithClientTrace(
    84  			ctx, httpClientTracer,
    85  		),
    86  	)
    87  	response, err = c.Next(r)
    88  
    89  	// If it is now using default trace provider, it then does no complex tracing jobs.
    90  	if isUsingDefaultProvider {
    91  		return
    92  	}
    93  
    94  	if err != nil {
    95  		span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
    96  	}
    97  	if response == nil || response.Response == nil {
    98  		return
    99  	}
   100  
   101  	span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
   102  		attribute.String(
   103  			tracingEventHttpResponseHeaders,
   104  			gconv.String(httputil.HeaderToMap(response.Header)),
   105  		),
   106  	))
   107  	return
   108  }