From bb15dfc2a54f0e488f039fe565400edb51c6c201 Mon Sep 17 00:00:00 2001 From: Jan Wytze Zuidema Date: Wed, 17 Apr 2024 13:56:11 +0200 Subject: [PATCH] Update code to work with the newest Sentry SDK and add more details to the span/transaction --- client_interceptors.go | 20 ++++++++---- go.mod | 2 +- go.sum | 1 + server_interceptors.go | 70 ++++++++++++++++++++++++++++-------------- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/client_interceptors.go b/client_interceptors.go index 623bc07..8142b64 100644 --- a/client_interceptors.go +++ b/client_interceptors.go @@ -29,13 +29,18 @@ func UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor { operationName = o.OperationNameOverride } - span := sentry.StartSpan(ctx, operationName) + span := sentry.StartSpan(ctx, operationName, sentry.WithDescription(method)) + span.SetData("grpc.request.method", method) ctx = span.Context() md, ok := metadata.FromOutgoingContext(ctx) if ok { - md.Append("sentry-trace", span.ToSentryTrace()) + md.Append(sentry.SentryTraceHeader, span.ToSentryTrace()) + md.Append(sentry.SentryBaggageHeader, span.ToBaggage()) } else { - md = metadata.Pairs("sentry-trace", span.ToSentryTrace()) + md = metadata.Pairs( + sentry.SentryTraceHeader, span.ToSentryTrace(), + sentry.SentryBaggageHeader, span.ToBaggage(), + ) } ctx = metadata.NewOutgoingContext(ctx, md) defer span.Finish() @@ -70,13 +75,16 @@ func StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor { operationName = o.OperationNameOverride } - span := sentry.StartSpan(ctx, operationName) + span := sentry.StartSpan(ctx, operationName, sentry.WithDescription(method)) + span.SetData("grpc.request.method", method) ctx = span.Context() md, ok := metadata.FromOutgoingContext(ctx) if ok { - md.Append("sentry-trace", span.ToSentryTrace()) + md.Append(sentry.SentryTraceHeader, span.ToSentryTrace()) + md.Append(sentry.SentryBaggageHeader, span.ToBaggage()) } else { - md = metadata.Pairs("sentry-trace", span.ToSentryTrace()) + md = metadata.Pairs(sentry.SentryTraceHeader, span.ToSentryTrace()) + md = metadata.Pairs(sentry.SentryBaggageHeader, span.ToBaggage()) } ctx = metadata.NewOutgoingContext(ctx, md) defer span.Finish() diff --git a/go.mod b/go.mod index 6a0f8a2..870dec6 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/johnbellone/grpc-middleware-sentry go 1.17 require ( - github.com/getsentry/sentry-go v0.20.0 + github.com/getsentry/sentry-go v0.27.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 google.golang.org/grpc v1.56.3 ) diff --git a/go.sum b/go.sum index ddd81ba..a216e99 100644 --- a/go.sum +++ b/go.sum @@ -689,6 +689,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ= github.com/getsentry/sentry-go v0.20.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= diff --git a/server_interceptors.go b/server_interceptors.go index fb21e7b..0fafb5d 100644 --- a/server_interceptors.go +++ b/server_interceptors.go @@ -47,9 +47,20 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor { } md, _ := metadata.FromIncomingContext(ctx) // nil check in ContinueFromGrpcMetadata - span := sentry.StartSpan(ctx, operationName, ContinueFromGrpcMetadata(md)) - ctx = span.Context() - defer span.Finish() + + // Use the FullMethod as transaction name and as description. This way the FullMethod will show up under + // the span, and under the transaction. + tx := sentry.StartTransaction( + ctx, + info.FullMethod, + sentry.WithOpName(operationName), + sentry.WithDescription(info.FullMethod), + sentry.WithTransactionSource(sentry.SourceURL), + ContinueFromGrpcMetadata(md), + ) + tx.SetData("grpc.request.method", info.FullMethod) + ctx = tx.Context() + defer tx.Finish() // TODO: Perhaps makes sense to use SetRequestBody instead? hub.Scope().SetExtra("requestBody", req) @@ -63,8 +74,11 @@ func UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor { } hub.CaptureException(err) + + // Always sample when an error has occurred. + tx.Sampled = sentry.SampledTrue } - span.Status = toSpanStatus(status.Code(err)) + tx.Status = toSpanStatus(status.Code(err)) return resp, err } @@ -90,9 +104,20 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { } md, _ := metadata.FromIncomingContext(ctx) // nil check in ContinueFromGrpcMetadata - span := sentry.StartSpan(ctx, operationName, ContinueFromGrpcMetadata(md)) - ctx = span.Context() - defer span.Finish() + + // Use the FullMethod as transaction name and as description. This way the FullMethod will show up under + // the span, and under the transaction. + tx := sentry.StartTransaction( + ctx, + info.FullMethod, + sentry.WithOpName(operationName), + sentry.WithDescription(info.FullMethod), + sentry.WithTransactionSource(sentry.SourceURL), + ContinueFromGrpcMetadata(md), + ) + tx.SetData("grpc.request.method", info.FullMethod) + ctx = tx.Context() + defer tx.Finish() stream := grpc_middleware.WrapServerStream(ss) stream.WrappedContext = ctx @@ -107,8 +132,11 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { } hub.CaptureException(err) + + // Always sample when an error has occurred. + tx.Sampled = sentry.SampledTrue } - span.Status = toSpanStatus(status.Code(err)) + tx.Status = toSpanStatus(status.Code(err)) return err } @@ -118,23 +146,19 @@ func StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { // an existing trace. If it cannot detect an existing trace in the request, the // span will be left unchanged. func ContinueFromGrpcMetadata(md metadata.MD) sentry.SpanOption { - return func(s *sentry.Span) { - if md == nil { - return - } + if md == nil { + return nil + } - trace, ok := md["sentry-trace"] - if !ok { - return - } - if len(trace) != 1 { - return - } - if trace[0] == "" { - return - } - updateFromSentryTrace(s, []byte(trace[0])) + var trace, baggage string + if traceMetadata, ok := md[sentry.SentryTraceHeader]; ok && len(traceMetadata) > 0 { + trace = traceMetadata[0] } + if baggageMetadata, ok := md[sentry.SentryBaggageHeader]; ok && len(baggageMetadata) > 0 { + baggage = baggageMetadata[0] + } + + return sentry.ContinueFromHeaders(trace, baggage) } // Re-export of functions from tracing.go of sentry-go