github.com/gogf/gf@v1.16.9/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  	"fmt"
    11  	"io/ioutil"
    12  	"net/http"
    13  
    14  	"github.com/gogf/gf"
    15  	"github.com/gogf/gf/internal/utils"
    16  	"github.com/gogf/gf/net/ghttp/internal/client"
    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.Server"
    30  	tracingEventHttpRequest         = "http.request"
    31  	tracingEventHttpRequestHeaders  = "http.request.headers"
    32  	tracingEventHttpRequestBaggage  = "http.request.baggage"
    33  	tracingEventHttpRequestBody     = "http.request.body"
    34  	tracingEventHttpResponse        = "http.response"
    35  	tracingEventHttpResponseHeaders = "http.response.headers"
    36  	tracingEventHttpResponseBody    = "http.response.body"
    37  )
    38  
    39  // MiddlewareClientTracing is a client middleware that enables tracing feature using standards of OpenTelemetry.
    40  func MiddlewareClientTracing(c *Client, r *http.Request) (*ClientResponse, error) {
    41  	return client.MiddlewareTracing(c, r)
    42  }
    43  
    44  // MiddlewareServerTracing is a serer middleware that enables tracing feature using standards of OpenTelemetry.
    45  func MiddlewareServerTracing(r *Request) {
    46  	tr := otel.GetTracerProvider().Tracer(tracingInstrumentName, trace.WithInstrumentationVersion(gf.VERSION))
    47  	ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
    48  	ctx, span := tr.Start(ctx, r.URL.String(), trace.WithSpanKind(trace.SpanKindServer))
    49  	defer span.End()
    50  
    51  	span.SetAttributes(gtrace.CommonLabels()...)
    52  
    53  	// Inject tracing context.
    54  	r.SetCtx(ctx)
    55  
    56  	// Request content logging.
    57  	reqBodyContentBytes, _ := ioutil.ReadAll(r.Body)
    58  	r.Body = utils.NewReadCloser(reqBodyContentBytes, false)
    59  
    60  	span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
    61  		attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))),
    62  		attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()),
    63  		attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
    64  			string(reqBodyContentBytes),
    65  			gtrace.MaxContentLogSize(),
    66  			"...",
    67  		)),
    68  	))
    69  
    70  	// Continue executing.
    71  	r.Middleware.Next()
    72  
    73  	// Error logging.
    74  	if err := r.GetError(); err != nil {
    75  		span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
    76  	}
    77  	// Response content logging.
    78  	var resBodyContent string
    79  	resBodyContent = r.Response.BufferString()
    80  	resBodyContent = gstr.StrLimit(
    81  		r.Response.BufferString(),
    82  		gtrace.MaxContentLogSize(),
    83  		"...",
    84  	)
    85  
    86  	span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
    87  		attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))),
    88  		attribute.String(tracingEventHttpResponseBody, resBodyContent),
    89  	))
    90  	return
    91  }