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  }