Repository: grpc/grpc-go
File: stats/opentelemetry/opentelemetry.go (Go)

Code before:
			grpc.WithChainStreamInterceptor(tracingHandler.streamInterceptor),
			grpc.WithStatsHandler(tracingHandler),
		)
	}
	return joinDialOptions(do...)
}

var joinServerOptions = internal.JoinServerOptions.(func(...grpc.ServerOption) grpc.ServerOption)

// ServerOption returns a server option which enables OpenTelemetry
// instrumentation code for a grpc.Server.
//
// Server applications interested in instrumenting their grpc.Server should pass
// the server option returned from this function as an argument to
// grpc.NewServer().
//
// For the metrics supported by this instrumentation code, specify the server
// metrics to record in metrics options. Also provide an implementation of a
// MeterProvider. If the passed in Meter Provider does not have the view
// configured for an individual metric turned on, the API call in this component
// will create a default view for that metric.
func ServerOption(o Options) grpc.ServerOption {
	var so []grpc.ServerOption

	if o.isMetricsEnabled() {
		metricsHandler := &serverStatsHandler{
			MetricsRecorder: &registryMetrics{optionalLabels: o.MetricsOptions.OptionalLabels},
			options:         o,
			serverMetrics:   serverMetrics{},
		}
		metricsHandler.initializeMetrics()
		so = append(so,
			grpc.ChainUnaryInterceptor(metricsHandler.unaryInterceptor),
			grpc.ChainStreamInterceptor(metricsHandler.streamInterceptor),
			grpc.StatsHandler(metricsHandler),
		)
	}

	if o.isTracingEnabled() {
		tracingHandler := &serverTracingHandler{
			options: o,
		}
		tracingHandler.initializeTraces()
		so = append(so,
			grpc.ChainUnaryInterceptor(tracingHandler.unaryInterceptor),
			grpc.ChainStreamInterceptor(tracingHandler.streamInterceptor),
			grpc.StatsHandler(tracingHandler),
		)
	}

	return joinServerOptions(so...)

Review comment (suggestion):
same comment as DialOption. Please keep the clientStatsHandler stuff as is and only add the tracing part.

Code after:
// instrumentation code for a grpc.Server.
//
// Server applications interested in instrumenting their grpc.Server should pass
// the server option returned from this function as an argument to
// grpc.NewServer().
//
// For the metrics supported by this instrumentation code, specify the server
// metrics to record in metrics options. Also provide an implementation of a
// MeterProvider. If the passed in Meter Provider does not have the view
// configured for an individual metric turned on, the API call in this component
// will create a default view for that metric.
//
// For the traces supported by this instrumentation code, provide an
// implementation of a TextMapPropagator and OpenTelemetry TracerProvider.
func ServerOption(o Options) grpc.ServerOption {
	var metricsOpts, tracingOpts []grpc.ServerOption

	if o.isMetricsEnabled() {
		metricsHandler := &serverMetricsHandler{options: o}
		metricsHandler.initializeMetrics()
		metricsOpts = append(metricsOpts, grpc.ChainUnaryInterceptor(metricsHandler.unaryInterceptor), grpc.ChainStreamInterceptor(metricsHandler.streamInterceptor), grpc.StatsHandler(metricsHandler))
	}
	if o.isTracingEnabled() {
		tracingHandler := &serverTracingHandler{options: o}
		tracingHandler.initializeTraces()
		tracingOpts = append(tracingOpts, grpc.StatsHandler(tracingHandler))
	}
	return joinServerOptions(append(metricsOpts, tracingOpts...)...)
}

// callInfo is information pertaining to the lifespan of the RPC client side.
type callInfo struct {
	target string

	method string

	// nameResolutionEventAdded is set when the resolver delay trace event
	// is added. Prevents duplicate events, since it is reported per-attempt.
	nameResolutionEventAdded atomic.Bool
}

type callInfoKey struct{}

func setCallInfo(ctx context.Context, ci *callInfo) context.Context {
	return context.WithValue(ctx, callInfoKey{}, ci)
}

// getCallInfo returns the callInfo stored in the context, or nil
// if there isn't one.
func getCallInfo(ctx context.Context) *callInfo {
	ci, _ := ctx.Value(callInfoKey{}).(*callInfo)