github.com/gogf/gf@v1.16.9/net/ghttp/internal/client/client_tracing_tracer.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  	"context"
    11  	"crypto/tls"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"net/http"
    15  	"net/http/httptrace"
    16  	"net/textproto"
    17  	"strings"
    18  	"sync"
    19  
    20  	"github.com/gogf/gf/internal/utils"
    21  	"github.com/gogf/gf/net/gtrace"
    22  	"github.com/gogf/gf/text/gstr"
    23  	"github.com/gogf/gf/util/gconv"
    24  	"go.opentelemetry.io/otel/attribute"
    25  	"go.opentelemetry.io/otel/codes"
    26  	"go.opentelemetry.io/otel/trace"
    27  )
    28  
    29  type clientTracer struct {
    30  	context.Context
    31  	span        trace.Span
    32  	request     *http.Request
    33  	requestBody []byte
    34  	headers     map[string]interface{}
    35  	mtx         sync.Mutex
    36  }
    37  
    38  func newClientTrace(ctx context.Context, span trace.Span, request *http.Request) *httptrace.ClientTrace {
    39  	ct := &clientTracer{
    40  		Context: ctx,
    41  		span:    span,
    42  		request: request,
    43  		headers: make(map[string]interface{}),
    44  	}
    45  
    46  	reqBodyContent, _ := ioutil.ReadAll(ct.request.Body)
    47  	ct.requestBody = reqBodyContent
    48  	ct.request.Body = utils.NewReadCloser(reqBodyContent, false)
    49  
    50  	return &httptrace.ClientTrace{
    51  		GetConn:              ct.getConn,
    52  		GotConn:              ct.gotConn,
    53  		PutIdleConn:          ct.putIdleConn,
    54  		GotFirstResponseByte: ct.gotFirstResponseByte,
    55  		Got100Continue:       ct.got100Continue,
    56  		Got1xxResponse:       ct.got1xxResponse,
    57  		DNSStart:             ct.dnsStart,
    58  		DNSDone:              ct.dnsDone,
    59  		ConnectStart:         ct.connectStart,
    60  		ConnectDone:          ct.connectDone,
    61  		TLSHandshakeStart:    ct.tlsHandshakeStart,
    62  		TLSHandshakeDone:     ct.tlsHandshakeDone,
    63  		WroteHeaderField:     ct.wroteHeaderField,
    64  		WroteHeaders:         ct.wroteHeaders,
    65  		Wait100Continue:      ct.wait100Continue,
    66  		WroteRequest:         ct.wroteRequest,
    67  	}
    68  }
    69  
    70  func (ct *clientTracer) getConn(host string) {
    71  
    72  }
    73  
    74  func (ct *clientTracer) gotConn(info httptrace.GotConnInfo) {
    75  	ct.span.SetAttributes(
    76  		attribute.String(tracingAttrHttpAddressRemote, info.Conn.RemoteAddr().String()),
    77  		attribute.String(tracingAttrHttpAddressLocal, info.Conn.LocalAddr().String()),
    78  	)
    79  }
    80  
    81  func (ct *clientTracer) putIdleConn(err error) {
    82  	if err != nil {
    83  		ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
    84  	}
    85  }
    86  
    87  func (ct *clientTracer) dnsStart(info httptrace.DNSStartInfo) {
    88  	ct.span.SetAttributes(
    89  		attribute.String(tracingAttrHttpDnsStart, info.Host),
    90  	)
    91  }
    92  
    93  func (ct *clientTracer) dnsDone(info httptrace.DNSDoneInfo) {
    94  	var buffer strings.Builder
    95  	for _, v := range info.Addrs {
    96  		if buffer.Len() != 0 {
    97  			buffer.WriteString(",")
    98  		}
    99  		buffer.WriteString(v.String())
   100  	}
   101  	if info.Err != nil {
   102  		ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
   103  	}
   104  	ct.span.SetAttributes(
   105  		attribute.String(tracingAttrHttpDnsDone, buffer.String()),
   106  	)
   107  }
   108  
   109  func (ct *clientTracer) connectStart(network, addr string) {
   110  	ct.span.SetAttributes(
   111  		attribute.String(tracingAttrHttpConnectStart, network+"@"+addr),
   112  	)
   113  }
   114  
   115  func (ct *clientTracer) connectDone(network, addr string, err error) {
   116  	if err != nil {
   117  		ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
   118  	}
   119  	ct.span.SetAttributes(
   120  		attribute.String(tracingAttrHttpConnectDone, network+"@"+addr),
   121  	)
   122  }
   123  
   124  func (ct *clientTracer) tlsHandshakeStart() {
   125  
   126  }
   127  
   128  func (ct *clientTracer) tlsHandshakeDone(_ tls.ConnectionState, err error) {
   129  	if err != nil {
   130  		ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, err))
   131  	}
   132  }
   133  
   134  func (ct *clientTracer) wroteHeaderField(k string, v []string) {
   135  	if len(v) > 1 {
   136  		ct.headers[k] = v
   137  	} else {
   138  		ct.headers[k] = v[0]
   139  	}
   140  }
   141  
   142  func (ct *clientTracer) wroteHeaders() {
   143  
   144  }
   145  
   146  func (ct *clientTracer) wroteRequest(info httptrace.WroteRequestInfo) {
   147  	if info.Err != nil {
   148  		ct.span.SetStatus(codes.Error, fmt.Sprintf(`%+v`, info.Err))
   149  	}
   150  
   151  	ct.span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
   152  		attribute.String(tracingEventHttpRequestHeaders, gconv.String(ct.headers)),
   153  		attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context).String()),
   154  		attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
   155  			string(ct.requestBody),
   156  			gtrace.MaxContentLogSize(),
   157  			"...",
   158  		)),
   159  	))
   160  }
   161  
   162  func (ct *clientTracer) got100Continue() {
   163  
   164  }
   165  
   166  func (ct *clientTracer) wait100Continue() {
   167  
   168  }
   169  
   170  func (ct *clientTracer) gotFirstResponseByte() {
   171  
   172  }
   173  
   174  func (ct *clientTracer) got1xxResponse(code int, header textproto.MIMEHeader) error {
   175  	return nil
   176  }