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

Code before:
	server := internal.ServerFromContext.(func(context.Context) *grpc.Server)(ctx)
	if server == nil { // Shouldn't happen, defensive programming.
		logger.Error("ctx passed into server side stats handler has no grpc server ref")
		method = "other"
	} else {
		isRegisteredMethod := internal.IsRegisteredMethod.(func(*grpc.Server, string) bool)
		if !isRegisteredMethod(server, method) {
			method = "other"
		}
	}

	ai := &attemptInfo{
		startTime: time.Now(),
		method:    removeLeadingSlash(method),
	}
	if h.options.isTracingEnabled() {
		ctx, ai = h.traceTagRPC(ctx, ai)
	}
	return setRPCInfo(ctx, &rpcInfo{
		ai: ai,
	})
}

// HandleRPC implements per RPC tracing and stats implementation.
func (h *serverStatsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
	if h.options.isMetricsEnabled() {
		metricsHandler := &serverMetricsStatsHandler{serverStatsHandler: h}
		metricsHandler.HandleRPC(ctx, rs)
	}
	if h.options.isTracingEnabled() {
		tracingHandler := &serverTracingStatsHandler{serverStatsHandler: h}
		tracingHandler.HandleRPC(ctx, rs)
	}
}

// HandleRPC implements per RPC stats handling for metrics.
func (h *serverMetricsStatsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
	ri := getRPCInfo(ctx)
	if ri == nil {
		logger.Error("ctx passed into server metrics stats handler metrics event handling has no server call data present")
		return
	}
	h.processRPCData(ctx, rs, ri.ai)
}

// HandleRPC implements per RPC tracing handling for tracing.
func (h *serverTracingStatsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
	ri := getRPCInfo(ctx)
	if ri == nil {
		logger.Error("ctx passed into server tracing stats handler tracing event handling has no server call data present")
		return

Review comment (suggestion):
we should have separate HandleRPC for metrics and trace statsHandlers instead of having common which requires to check what is enabled etc.

Code after:
			method = "other"
		}
	}
	ctx, ai := getOrCreateRPCAttemptInfo(ctx)
	ai.startTime = time.Now()
	ai.method = removeLeadingSlash(method)

	return setRPCInfo(ctx, &rpcInfo{ai: ai})
}

// HandleRPC handles per RPC stats implementation.
func (h *serverMetricsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
	ri := getRPCInfo(ctx)
	if ri == nil {
		logger.Error("ctx passed into server side stats handler metrics event handling has no server call data present")
		return
	}
	h.processRPCData(ctx, rs, ri.ai)
}

func (h *serverMetricsHandler) processRPCData(ctx context.Context, s stats.RPCStats, ai *attemptInfo) {
	switch st := s.(type) {
	case *stats.InHeader:
		if ai.pluginOptionLabels == nil && h.options.MetricsOptions.pluginOption != nil {
			labels := h.options.MetricsOptions.pluginOption.GetLabels(st.Header)
			if labels == nil {
				labels = map[string]string{} // Shouldn't return a nil map. Make it empty if so to ignore future Get Calls for this Attempt.
			}
			ai.pluginOptionLabels = labels
		}
		attrs := otelmetric.WithAttributeSet(otelattribute.NewSet(
			otelattribute.String("grpc.method", ai.method),
		))
		h.serverMetrics.callStarted.Add(ctx, 1, attrs)
	case *stats.OutPayload:
		atomic.AddInt64(&ai.sentCompressedBytes, int64(st.CompressedLength))
	case *stats.InPayload:
		atomic.AddInt64(&ai.recvCompressedBytes, int64(st.CompressedLength))
	case *stats.End:
		h.processRPCEnd(ctx, ai, st)
	default:
	}
}

func (h *serverMetricsHandler) processRPCEnd(ctx context.Context, ai *attemptInfo, e *stats.End) {
	latency := float64(time.Since(ai.startTime)) / float64(time.Second)
	st := "OK"
	if e.Error != nil {
		s, _ := status.FromError(e.Error)
		st = canonicalString(s.Code())
	}