...

Source file src/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/config.go

Documentation: go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc

     1  // Copyright The OpenTelemetry Authors
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package otelgrpc // import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
     5  
     6  import (
     7  	"go.opentelemetry.io/otel"
     8  	"go.opentelemetry.io/otel/attribute"
     9  	"go.opentelemetry.io/otel/metric"
    10  	"go.opentelemetry.io/otel/metric/noop"
    11  	"go.opentelemetry.io/otel/propagation"
    12  	semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
    13  	"go.opentelemetry.io/otel/trace"
    14  )
    15  
    16  const (
    17  	// ScopeName is the instrumentation scope name.
    18  	ScopeName = "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
    19  	// GRPCStatusCodeKey is convention for numeric status code of a gRPC request.
    20  	GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
    21  )
    22  
    23  // Filter is a predicate used to determine whether a given request in
    24  // interceptor info should be traced. A Filter must return true if
    25  // the request should be traced.
    26  type Filter func(*InterceptorInfo) bool
    27  
    28  // config is a group of options for this instrumentation.
    29  type config struct {
    30  	Filter           Filter
    31  	Propagators      propagation.TextMapPropagator
    32  	TracerProvider   trace.TracerProvider
    33  	MeterProvider    metric.MeterProvider
    34  	SpanStartOptions []trace.SpanStartOption
    35  
    36  	ReceivedEvent bool
    37  	SentEvent     bool
    38  
    39  	tracer trace.Tracer
    40  	meter  metric.Meter
    41  
    42  	rpcDuration        metric.Float64Histogram
    43  	rpcRequestSize     metric.Int64Histogram
    44  	rpcResponseSize    metric.Int64Histogram
    45  	rpcRequestsPerRPC  metric.Int64Histogram
    46  	rpcResponsesPerRPC metric.Int64Histogram
    47  }
    48  
    49  // Option applies an option value for a config.
    50  type Option interface {
    51  	apply(*config)
    52  }
    53  
    54  // newConfig returns a config configured with all the passed Options.
    55  func newConfig(opts []Option, role string) *config {
    56  	c := &config{
    57  		Propagators:    otel.GetTextMapPropagator(),
    58  		TracerProvider: otel.GetTracerProvider(),
    59  		MeterProvider:  otel.GetMeterProvider(),
    60  	}
    61  	for _, o := range opts {
    62  		o.apply(c)
    63  	}
    64  
    65  	c.tracer = c.TracerProvider.Tracer(
    66  		ScopeName,
    67  		trace.WithInstrumentationVersion(SemVersion()),
    68  	)
    69  
    70  	c.meter = c.MeterProvider.Meter(
    71  		ScopeName,
    72  		metric.WithInstrumentationVersion(Version()),
    73  		metric.WithSchemaURL(semconv.SchemaURL),
    74  	)
    75  
    76  	var err error
    77  	c.rpcDuration, err = c.meter.Float64Histogram("rpc."+role+".duration",
    78  		metric.WithDescription("Measures the duration of inbound RPC."),
    79  		metric.WithUnit("ms"))
    80  	if err != nil {
    81  		otel.Handle(err)
    82  		if c.rpcDuration == nil {
    83  			c.rpcDuration = noop.Float64Histogram{}
    84  		}
    85  	}
    86  
    87  	c.rpcRequestSize, err = c.meter.Int64Histogram("rpc."+role+".request.size",
    88  		metric.WithDescription("Measures size of RPC request messages (uncompressed)."),
    89  		metric.WithUnit("By"))
    90  	if err != nil {
    91  		otel.Handle(err)
    92  		if c.rpcRequestSize == nil {
    93  			c.rpcRequestSize = noop.Int64Histogram{}
    94  		}
    95  	}
    96  
    97  	c.rpcResponseSize, err = c.meter.Int64Histogram("rpc."+role+".response.size",
    98  		metric.WithDescription("Measures size of RPC response messages (uncompressed)."),
    99  		metric.WithUnit("By"))
   100  	if err != nil {
   101  		otel.Handle(err)
   102  		if c.rpcResponseSize == nil {
   103  			c.rpcResponseSize = noop.Int64Histogram{}
   104  		}
   105  	}
   106  
   107  	c.rpcRequestsPerRPC, err = c.meter.Int64Histogram("rpc."+role+".requests_per_rpc",
   108  		metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
   109  		metric.WithUnit("{count}"))
   110  	if err != nil {
   111  		otel.Handle(err)
   112  		if c.rpcRequestsPerRPC == nil {
   113  			c.rpcRequestsPerRPC = noop.Int64Histogram{}
   114  		}
   115  	}
   116  
   117  	c.rpcResponsesPerRPC, err = c.meter.Int64Histogram("rpc."+role+".responses_per_rpc",
   118  		metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
   119  		metric.WithUnit("{count}"))
   120  	if err != nil {
   121  		otel.Handle(err)
   122  		if c.rpcResponsesPerRPC == nil {
   123  			c.rpcResponsesPerRPC = noop.Int64Histogram{}
   124  		}
   125  	}
   126  
   127  	return c
   128  }
   129  
   130  type propagatorsOption struct{ p propagation.TextMapPropagator }
   131  
   132  func (o propagatorsOption) apply(c *config) {
   133  	if o.p != nil {
   134  		c.Propagators = o.p
   135  	}
   136  }
   137  
   138  // WithPropagators returns an Option to use the Propagators when extracting
   139  // and injecting trace context from requests.
   140  func WithPropagators(p propagation.TextMapPropagator) Option {
   141  	return propagatorsOption{p: p}
   142  }
   143  
   144  type tracerProviderOption struct{ tp trace.TracerProvider }
   145  
   146  func (o tracerProviderOption) apply(c *config) {
   147  	if o.tp != nil {
   148  		c.TracerProvider = o.tp
   149  	}
   150  }
   151  
   152  // WithInterceptorFilter returns an Option to use the request filter.
   153  //
   154  // Deprecated: Use stats handlers instead.
   155  func WithInterceptorFilter(f Filter) Option {
   156  	return interceptorFilterOption{f: f}
   157  }
   158  
   159  type interceptorFilterOption struct {
   160  	f Filter
   161  }
   162  
   163  func (o interceptorFilterOption) apply(c *config) {
   164  	if o.f != nil {
   165  		c.Filter = o.f
   166  	}
   167  }
   168  
   169  // WithTracerProvider returns an Option to use the TracerProvider when
   170  // creating a Tracer.
   171  func WithTracerProvider(tp trace.TracerProvider) Option {
   172  	return tracerProviderOption{tp: tp}
   173  }
   174  
   175  type meterProviderOption struct{ mp metric.MeterProvider }
   176  
   177  func (o meterProviderOption) apply(c *config) {
   178  	if o.mp != nil {
   179  		c.MeterProvider = o.mp
   180  	}
   181  }
   182  
   183  // WithMeterProvider returns an Option to use the MeterProvider when
   184  // creating a Meter. If this option is not provide the global MeterProvider will be used.
   185  func WithMeterProvider(mp metric.MeterProvider) Option {
   186  	return meterProviderOption{mp: mp}
   187  }
   188  
   189  // Event type that can be recorded, see WithMessageEvents.
   190  type Event int
   191  
   192  // Different types of events that can be recorded, see WithMessageEvents.
   193  const (
   194  	ReceivedEvents Event = iota
   195  	SentEvents
   196  )
   197  
   198  type messageEventsProviderOption struct {
   199  	events []Event
   200  }
   201  
   202  func (m messageEventsProviderOption) apply(c *config) {
   203  	for _, e := range m.events {
   204  		switch e {
   205  		case ReceivedEvents:
   206  			c.ReceivedEvent = true
   207  		case SentEvents:
   208  			c.SentEvent = true
   209  		}
   210  	}
   211  }
   212  
   213  // WithMessageEvents configures the Handler to record the specified events
   214  // (span.AddEvent) on spans. By default only summary attributes are added at the
   215  // end of the request.
   216  //
   217  // Valid events are:
   218  //   - ReceivedEvents: Record the number of bytes read after every gRPC read operation.
   219  //   - SentEvents: Record the number of bytes written after every gRPC write operation.
   220  func WithMessageEvents(events ...Event) Option {
   221  	return messageEventsProviderOption{events: events}
   222  }
   223  
   224  type spanStartOption struct{ opts []trace.SpanStartOption }
   225  
   226  func (o spanStartOption) apply(c *config) {
   227  	c.SpanStartOptions = append(c.SpanStartOptions, o.opts...)
   228  }
   229  
   230  // WithSpanOptions configures an additional set of
   231  // trace.SpanOptions, which are applied to each new span.
   232  func WithSpanOptions(opts ...trace.SpanStartOption) Option {
   233  	return spanStartOption{opts}
   234  }
   235  

View as plain text