config.go

  1// Copyright The OpenTelemetry Authors
  2// SPDX-License-Identifier: Apache-2.0
  3
  4package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
  5
  6import (
  7	"context"
  8	"net/http"
  9	"net/http/httptrace"
 10
 11	"go.opentelemetry.io/otel/attribute"
 12
 13	"go.opentelemetry.io/otel"
 14	"go.opentelemetry.io/otel/metric"
 15	"go.opentelemetry.io/otel/propagation"
 16	"go.opentelemetry.io/otel/trace"
 17)
 18
 19// ScopeName is the instrumentation scope name.
 20const ScopeName = "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
 21
 22// config represents the configuration options available for the http.Handler
 23// and http.Transport types.
 24type config struct {
 25	ServerName        string
 26	Tracer            trace.Tracer
 27	Meter             metric.Meter
 28	Propagators       propagation.TextMapPropagator
 29	SpanStartOptions  []trace.SpanStartOption
 30	PublicEndpoint    bool
 31	PublicEndpointFn  func(*http.Request) bool
 32	ReadEvent         bool
 33	WriteEvent        bool
 34	Filters           []Filter
 35	SpanNameFormatter func(string, *http.Request) string
 36	ClientTrace       func(context.Context) *httptrace.ClientTrace
 37
 38	TracerProvider     trace.TracerProvider
 39	MeterProvider      metric.MeterProvider
 40	MetricAttributesFn func(*http.Request) []attribute.KeyValue
 41}
 42
 43// Option interface used for setting optional config properties.
 44type Option interface {
 45	apply(*config)
 46}
 47
 48type optionFunc func(*config)
 49
 50func (o optionFunc) apply(c *config) {
 51	o(c)
 52}
 53
 54// newConfig creates a new config struct and applies opts to it.
 55func newConfig(opts ...Option) *config {
 56	c := &config{
 57		Propagators:   otel.GetTextMapPropagator(),
 58		MeterProvider: otel.GetMeterProvider(),
 59	}
 60	for _, opt := range opts {
 61		opt.apply(c)
 62	}
 63
 64	// Tracer is only initialized if manually specified. Otherwise, can be passed with the tracing context.
 65	if c.TracerProvider != nil {
 66		c.Tracer = newTracer(c.TracerProvider)
 67	}
 68
 69	c.Meter = c.MeterProvider.Meter(
 70		ScopeName,
 71		metric.WithInstrumentationVersion(Version()),
 72	)
 73
 74	return c
 75}
 76
 77// WithTracerProvider specifies a tracer provider to use for creating a tracer.
 78// If none is specified, the global provider is used.
 79func WithTracerProvider(provider trace.TracerProvider) Option {
 80	return optionFunc(func(cfg *config) {
 81		if provider != nil {
 82			cfg.TracerProvider = provider
 83		}
 84	})
 85}
 86
 87// WithMeterProvider specifies a meter provider to use for creating a meter.
 88// If none is specified, the global provider is used.
 89func WithMeterProvider(provider metric.MeterProvider) Option {
 90	return optionFunc(func(cfg *config) {
 91		if provider != nil {
 92			cfg.MeterProvider = provider
 93		}
 94	})
 95}
 96
 97// WithPublicEndpoint configures the Handler to link the span with an incoming
 98// span context. If this option is not provided, then the association is a child
 99// association instead of a link.
100func WithPublicEndpoint() Option {
101	return optionFunc(func(c *config) {
102		c.PublicEndpoint = true
103	})
104}
105
106// WithPublicEndpointFn runs with every request, and allows conditionally
107// configuring the Handler to link the span with an incoming span context. If
108// this option is not provided or returns false, then the association is a
109// child association instead of a link.
110// Note: WithPublicEndpoint takes precedence over WithPublicEndpointFn.
111func WithPublicEndpointFn(fn func(*http.Request) bool) Option {
112	return optionFunc(func(c *config) {
113		c.PublicEndpointFn = fn
114	})
115}
116
117// WithPropagators configures specific propagators. If this
118// option isn't specified, then the global TextMapPropagator is used.
119func WithPropagators(ps propagation.TextMapPropagator) Option {
120	return optionFunc(func(c *config) {
121		if ps != nil {
122			c.Propagators = ps
123		}
124	})
125}
126
127// WithSpanOptions configures an additional set of
128// trace.SpanOptions, which are applied to each new span.
129func WithSpanOptions(opts ...trace.SpanStartOption) Option {
130	return optionFunc(func(c *config) {
131		c.SpanStartOptions = append(c.SpanStartOptions, opts...)
132	})
133}
134
135// WithFilter adds a filter to the list of filters used by the handler.
136// If any filter indicates to exclude a request then the request will not be
137// traced. All filters must allow a request to be traced for a Span to be created.
138// If no filters are provided then all requests are traced.
139// Filters will be invoked for each processed request, it is advised to make them
140// simple and fast.
141func WithFilter(f Filter) Option {
142	return optionFunc(func(c *config) {
143		c.Filters = append(c.Filters, f)
144	})
145}
146
147type event int
148
149// Different types of events that can be recorded, see WithMessageEvents.
150const (
151	ReadEvents event = iota
152	WriteEvents
153)
154
155// WithMessageEvents configures the Handler to record the specified events
156// (span.AddEvent) on spans. By default only summary attributes are added at the
157// end of the request.
158//
159// Valid events are:
160//   - ReadEvents: Record the number of bytes read after every http.Request.Body.Read
161//     using the ReadBytesKey
162//   - WriteEvents: Record the number of bytes written after every http.ResponeWriter.Write
163//     using the WriteBytesKey
164func WithMessageEvents(events ...event) Option {
165	return optionFunc(func(c *config) {
166		for _, e := range events {
167			switch e {
168			case ReadEvents:
169				c.ReadEvent = true
170			case WriteEvents:
171				c.WriteEvent = true
172			}
173		}
174	})
175}
176
177// WithSpanNameFormatter takes a function that will be called on every
178// request and the returned string will become the Span Name.
179func WithSpanNameFormatter(f func(operation string, r *http.Request) string) Option {
180	return optionFunc(func(c *config) {
181		c.SpanNameFormatter = f
182	})
183}
184
185// WithClientTrace takes a function that returns client trace instance that will be
186// applied to the requests sent through the otelhttp Transport.
187func WithClientTrace(f func(context.Context) *httptrace.ClientTrace) Option {
188	return optionFunc(func(c *config) {
189		c.ClientTrace = f
190	})
191}
192
193// WithServerName returns an Option that sets the name of the (virtual) server
194// handling requests.
195func WithServerName(server string) Option {
196	return optionFunc(func(c *config) {
197		c.ServerName = server
198	})
199}
200
201// WithMetricAttributesFn returns an Option to set a function that maps an HTTP request to a slice of attribute.KeyValue.
202// These attributes will be included in metrics for every request.
203func WithMetricAttributesFn(metricAttributesFn func(r *http.Request) []attribute.KeyValue) Option {
204	return optionFunc(func(c *config) {
205		c.MetricAttributesFn = metricAttributesFn
206	})
207}