github.com/mier85/go-sensor@v1.30.1-0.20220920111756-9bf41b3bc7e0/adapters.go (about) 1 // (c) Copyright IBM Corp. 2021 2 // (c) Copyright Instana Inc. 2019 3 4 package instana 5 6 import ( 7 "context" 8 "net/http" 9 "runtime" 10 11 "github.com/opentracing/opentracing-go" 12 ot "github.com/opentracing/opentracing-go" 13 "github.com/opentracing/opentracing-go/ext" 14 otlog "github.com/opentracing/opentracing-go/log" 15 ) 16 17 // SpanSensitiveFunc is a function executed within a span context 18 // 19 // Deprecated: use instana.ContextWithSpan() and instana.SpanFromContext() to inject and retrieve spans 20 type SpanSensitiveFunc func(span ot.Span) 21 22 // ContextSensitiveFunc is a SpanSensitiveFunc that also takes context.Context 23 // 24 // Deprecated: use instana.ContextWithSpan() and instana.SpanFromContext() to inject and retrieve spans 25 type ContextSensitiveFunc func(span ot.Span, ctx context.Context) 26 27 // Tracer extends the opentracing.Tracer interface 28 type Tracer interface { 29 opentracing.Tracer 30 31 // Options gets the current tracer options 32 Options() TracerOptions 33 // Flush sends all finished spans to the agent 34 Flush(context.Context) error 35 } 36 37 // Sensor is used to inject tracing information into requests 38 type Sensor struct { 39 tracer ot.Tracer 40 logger LeveledLogger 41 } 42 43 // NewSensor creates a new instana.Sensor 44 func NewSensor(serviceName string) *Sensor { 45 return NewSensorWithTracer(NewTracerWithOptions( 46 &Options{ 47 Service: serviceName, 48 }, 49 )) 50 } 51 52 // NewSensorWithTracer returns a new instana.Sensor that uses provided tracer to report spans 53 func NewSensorWithTracer(tracer ot.Tracer) *Sensor { 54 return &Sensor{ 55 tracer: tracer, 56 logger: defaultLogger, 57 } 58 } 59 60 // Tracer returns the tracer instance for this sensor 61 func (s *Sensor) Tracer() ot.Tracer { 62 return s.tracer 63 } 64 65 // Logger returns the logger instance for this sensor 66 func (s *Sensor) Logger() LeveledLogger { 67 return s.logger 68 } 69 70 // SetLogger sets the logger for this sensor 71 func (s *Sensor) SetLogger(l LeveledLogger) { 72 s.logger = l 73 } 74 75 // TraceHandler is similar to TracingHandler in regards, that it wraps an existing http.HandlerFunc 76 // into a named instance to support capturing tracing information and data. The returned values are 77 // compatible with handler registration methods, e.g. http.Handle() 78 // 79 // Deprecated: please use instana.TracingHandlerFunc() instead 80 func (s *Sensor) TraceHandler(name, pattern string, handler http.HandlerFunc) (string, http.HandlerFunc) { 81 return pattern, s.TracingHandler(name, handler) 82 } 83 84 // TracingHandler wraps an existing http.HandlerFunc into a named instance to support capturing tracing 85 // information and response data 86 // 87 // Deprecated: please use instana.TracingHandlerFunc() instead 88 func (s *Sensor) TracingHandler(name string, handler http.HandlerFunc) http.HandlerFunc { 89 return TracingHandlerFunc(s, name, handler) 90 } 91 92 // TracingHttpRequest wraps an existing http.Request instance into a named instance to inject tracing and span 93 // header information into the actual HTTP wire transfer 94 // 95 // Deprecated: please use instana.RoundTripper() instead 96 func (s *Sensor) TracingHttpRequest(name string, parent, req *http.Request, client http.Client) (*http.Response, error) { 97 client.Transport = RoundTripper(s, client.Transport) 98 return client.Do(req.WithContext(context.Background())) 99 } 100 101 // WithTracingSpan takes the given SpanSensitiveFunc and executes it under the scope of a child span, which is 102 // injected as an argument when calling the function. It uses the name of the caller as a span operation name 103 // unless a non-empty value is provided 104 // 105 // Deprecated: please use instana.TracingHandlerFunc() to instrument an HTTP handler 106 func (s *Sensor) WithTracingSpan(operationName string, w http.ResponseWriter, req *http.Request, f SpanSensitiveFunc) { 107 if operationName == "" { 108 pc, _, _, _ := runtime.Caller(1) 109 f := runtime.FuncForPC(pc) 110 operationName = f.Name() 111 } 112 113 opts := []ot.StartSpanOption{ 114 ext.SpanKindRPCServer, 115 116 ot.Tags{ 117 string(ext.PeerHostname): req.Host, 118 string(ext.HTTPUrl): req.URL.Path, 119 string(ext.HTTPMethod): req.Method, 120 }, 121 } 122 123 wireContext, err := s.tracer.Extract(ot.HTTPHeaders, ot.HTTPHeadersCarrier(req.Header)) 124 switch err { 125 case nil: 126 opts = append(opts, ext.RPCServerOption(wireContext)) 127 case ot.ErrSpanContextNotFound: 128 s.Logger().Debug("no span context provided with ", req.Method, " ", req.URL.Path) 129 case ot.ErrUnsupportedFormat: 130 s.Logger().Info("unsupported span context format provided with ", req.Method, " ", req.URL.Path) 131 default: 132 s.Logger().Warn("failed to extract span context from the request:", err) 133 } 134 135 if ps, ok := SpanFromContext(req.Context()); ok { 136 opts = append(opts, ot.ChildOf(ps.Context())) 137 } 138 139 span := s.tracer.StartSpan(operationName, opts...) 140 defer span.Finish() 141 142 defer func() { 143 // Capture outgoing headers 144 s.tracer.Inject(span.Context(), ot.HTTPHeaders, ot.HTTPHeadersCarrier(w.Header())) 145 146 // Be sure to capture any kind of panic / error 147 if err := recover(); err != nil { 148 if e, ok := err.(error); ok { 149 span.LogFields(otlog.Error(e)) 150 } else { 151 span.LogFields(otlog.Object("error", err)) 152 } 153 154 // re-throw the panic 155 panic(err) 156 } 157 }() 158 159 f(span) 160 } 161 162 // WithTracingContext executes the given ContextSensitiveFunc and executes it under the scope of a newly created context.Context, 163 // that provides access to the parent span as 'parentSpan'. 164 // 165 // Deprecated: please use instana.TracingHandlerFunc() to instrument an HTTP handler 166 func (s *Sensor) WithTracingContext(name string, w http.ResponseWriter, req *http.Request, f ContextSensitiveFunc) { 167 s.WithTracingSpan(name, w, req, func(span ot.Span) { 168 f(span, ContextWithSpan(req.Context(), span)) 169 }) 170 }