opentelemetry-go-contrib
opentelemetry-go-contrib copied to clipboard
Filter or skip span status for some grpc codes
Problem Statement
Now grpc interceptor sets span error if handler returned one of codes Unknown
, DeadlineExceeded
, Unimplemented
, etc. But on NotFound
code span status won't be set, which is should be configurable. Or vice versa, you could avoid setting span error on certain codes.
Proposed Solution
Add custom CodeFromGRPCStatus function as ServerInterceptor option.
Something like that:
--- vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/config.go (index)
+++ vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/config.go (working tree)
@@ -42,6 +42,7 @@ type config struct {
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
+ CodeFromGRPCStatus CodeFromGRPCStatus
ReceivedEvent bool
SentEvent bool
@@ -61,6 +62,7 @@ func newConfig(opts []Option) *config {
Propagators: otel.GetTextMapPropagator(),
TracerProvider: otel.GetTracerProvider(),
MeterProvider: otel.GetMeterProvider(),
+ CodeFromGRPCStatus: serverStatus,
}
for _, o := range opts {
o.apply(c)
@@ -182,3 +184,14 @@ func (o spanStartOption) apply(c *config) {
func WithSpanOptions(opts ...trace.SpanStartOption) Option {
return spanStartOption{opts}
}
+
+
+type codeFromGRPCOption struct { codeFromGRPC CodeFromGRPCStatus }
+
+func (o codeFromGRPCOption) apply(c *config) {
+ c.CodeFromGRPCStatus = o.codeFromGRPC
+}
+
+func WithCodeFromGRPCStatus(codeFromGRPC CodeFromGRPCStatus) Option {
+ return codeFromGRPCOption{codeFromGRPC: codeFromGRPC}
+}
--- vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go (index)
+++ vendor/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/interceptor.go (working tree)
@@ -376,8 +376,8 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor {
resp, err := handler(ctx, req)
if err != nil {
s, _ := status.FromError(err)
- statusCode, msg := serverStatus(s)
- span.SetStatus(statusCode, msg)
+ code, msg := cfg.CodeFromGRPCStatus(s)
+ span.SetStatus(code, msg)
span.SetAttributes(statusCodeAttr(s.Code()))
if cfg.SentEvent {
messageSent.Event(ctx, 1, s.Proto())
@@ -487,8 +487,8 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor {
err := handler(srv, wrapServerStream(ctx, ss, cfg))
if err != nil {
s, _ := status.FromError(err)
- statusCode, msg := serverStatus(s)
- span.SetStatus(statusCode, msg)
+ code, msg := cfg.CodeFromGRPCStatus(s)
+ span.SetStatus(code, msg)
span.SetAttributes(statusCodeAttr(s.Code()))
} else {
span.SetAttributes(statusCodeAttr(grpc_codes.OK))
@@ -553,6 +553,8 @@ func statusCodeAttr(c grpc_codes.Code) attribute.KeyValue {
return GRPCStatusCodeKey.Int64(int64(c))
}
+type CodeFromGRPCStatus func (grpcStatus *status.Status) (codes.Code, string)
+
// serverStatus returns a span status code and message for a given gRPC
// status code. It maps specific gRPC status codes to a corresponding span
// status code and message. This function is intended for use on the server
The gRPC status code mapping to span status is defined strongly in the spec: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/grpc.md#grpc-status. Unless changes to the spec doubt this instrumentation would change.
Changing this could create side effects with vendor backend implementations. I don't really recommend changing this mapping behavior but you could attempt to alter this by either using a custom fork of the library or play around with otel collector processors (e.g. transformprocessor)