mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
* Bump github.com/opentracing-contrib/go-grpc Bumps [github.com/opentracing-contrib/go-grpc](https://github.com/opentracing-contrib/go-grpc) from 0.0.0-20210225150812-73cb765af46e to 0.1.0. - [Release notes](https://github.com/opentracing-contrib/go-grpc/releases) - [Commits](https://github.com/opentracing-contrib/go-grpc/commits/v0.1.0) --- updated-dependencies: - dependency-name: github.com/opentracing-contrib/go-grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> * Update serverless gomod --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: tempo-gh-bot[bot] <[email protected]>
143 lines
4.8 KiB
Go
143 lines
4.8 KiB
Go
package otgrpc
|
|
|
|
import (
|
|
"context"
|
|
|
|
opentracing "github.com/opentracing/opentracing-go"
|
|
"github.com/opentracing/opentracing-go/ext"
|
|
"github.com/opentracing/opentracing-go/log"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/metadata"
|
|
)
|
|
|
|
// OpenTracingServerInterceptor returns a grpc.UnaryServerInterceptor suitable
|
|
// for use in a grpc.NewServer call.
|
|
//
|
|
// For example:
|
|
//
|
|
// s := grpc.NewServer(
|
|
// ..., // (existing ServerOptions)
|
|
// grpc.UnaryInterceptor(otgrpc.OpenTracingServerInterceptor(tracer)))
|
|
//
|
|
// All gRPC server spans will look for an OpenTracing SpanContext in the gRPC
|
|
// metadata; if found, the server span will act as the ChildOf that RPC
|
|
// SpanContext.
|
|
//
|
|
// Root or not, the server Span will be embedded in the context.Context for the
|
|
// application-specific gRPC handler(s) to access.
|
|
func OpenTracingServerInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.UnaryServerInterceptor {
|
|
otgrpcOpts := newOptions()
|
|
otgrpcOpts.apply(optFuncs...)
|
|
return func(
|
|
ctx context.Context,
|
|
req interface{},
|
|
info *grpc.UnaryServerInfo,
|
|
handler grpc.UnaryHandler,
|
|
) (resp interface{}, err error) {
|
|
spanContext, _ := extractSpanContext(ctx, tracer)
|
|
// if err != nil && !errors.Is(err, opentracing.ErrSpanContextNotFound) {
|
|
// // TODO: establish some sort of error reporting mechanism here. We
|
|
// // don't know where to put such an error and must rely on Tracer
|
|
// // implementations to do something appropriate for the time being.
|
|
// }
|
|
if otgrpcOpts.inclusionFunc != nil &&
|
|
!otgrpcOpts.inclusionFunc(spanContext, info.FullMethod, req, nil) {
|
|
return handler(ctx, req)
|
|
}
|
|
serverSpan := tracer.StartSpan(
|
|
info.FullMethod,
|
|
ext.RPCServerOption(spanContext),
|
|
gRPCComponentTag,
|
|
)
|
|
defer serverSpan.Finish()
|
|
|
|
ctx = opentracing.ContextWithSpan(ctx, serverSpan)
|
|
if otgrpcOpts.logPayloads {
|
|
serverSpan.LogFields(log.Object("gRPC request", req))
|
|
}
|
|
resp, err = handler(ctx, req)
|
|
if err == nil {
|
|
if otgrpcOpts.logPayloads {
|
|
serverSpan.LogFields(log.Object("gRPC response", resp))
|
|
}
|
|
} else {
|
|
SetSpanTags(serverSpan, err, false)
|
|
serverSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
|
|
}
|
|
if otgrpcOpts.decorator != nil {
|
|
otgrpcOpts.decorator(ctx, serverSpan, info.FullMethod, req, resp, err)
|
|
}
|
|
return resp, err
|
|
}
|
|
}
|
|
|
|
// OpenTracingStreamServerInterceptor returns a grpc.StreamServerInterceptor suitable
|
|
// for use in a grpc.NewServer call. The interceptor instruments streaming RPCs by
|
|
// creating a single span to correspond to the lifetime of the RPC's stream.
|
|
//
|
|
// For example:
|
|
//
|
|
// s := grpc.NewServer(
|
|
// ..., // (existing ServerOptions)
|
|
// grpc.StreamInterceptor(otgrpc.OpenTracingStreamServerInterceptor(tracer)))
|
|
//
|
|
// All gRPC server spans will look for an OpenTracing SpanContext in the gRPC
|
|
// metadata; if found, the server span will act as the ChildOf that RPC
|
|
// SpanContext.
|
|
//
|
|
// Root or not, the server Span will be embedded in the context.Context for the
|
|
// application-specific gRPC handler(s) to access.
|
|
func OpenTracingStreamServerInterceptor(tracer opentracing.Tracer, optFuncs ...Option) grpc.StreamServerInterceptor {
|
|
otgrpcOpts := newOptions()
|
|
otgrpcOpts.apply(optFuncs...)
|
|
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
|
spanContext, _ := extractSpanContext(ss.Context(), tracer)
|
|
// if err != nil && !errors.Is(err, opentracing.ErrSpanContextNotFound) {
|
|
// // TODO: establish some sort of error reporting mechanism here. We
|
|
// // don't know where to put such an error and must rely on Tracer
|
|
// // implementations to do something appropriate for the time being.
|
|
// }
|
|
if otgrpcOpts.inclusionFunc != nil &&
|
|
!otgrpcOpts.inclusionFunc(spanContext, info.FullMethod, nil, nil) {
|
|
return handler(srv, ss)
|
|
}
|
|
|
|
serverSpan := tracer.StartSpan(
|
|
info.FullMethod,
|
|
ext.RPCServerOption(spanContext),
|
|
gRPCComponentTag,
|
|
)
|
|
defer serverSpan.Finish()
|
|
ss = &openTracingServerStream{
|
|
ServerStream: ss,
|
|
ctx: opentracing.ContextWithSpan(ss.Context(), serverSpan),
|
|
}
|
|
err := handler(srv, ss)
|
|
if err != nil {
|
|
SetSpanTags(serverSpan, err, false)
|
|
serverSpan.LogFields(log.String("event", "error"), log.String("message", err.Error()))
|
|
}
|
|
if otgrpcOpts.decorator != nil {
|
|
otgrpcOpts.decorator(ss.Context(), serverSpan, info.FullMethod, nil, nil, err)
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
|
|
type openTracingServerStream struct {
|
|
grpc.ServerStream
|
|
ctx context.Context
|
|
}
|
|
|
|
func (ss *openTracingServerStream) Context() context.Context {
|
|
return ss.ctx
|
|
}
|
|
|
|
func extractSpanContext(ctx context.Context, tracer opentracing.Tracer) (opentracing.SpanContext, error) {
|
|
md, ok := metadata.FromIncomingContext(ctx)
|
|
if !ok {
|
|
md = metadata.New(nil)
|
|
}
|
|
return tracer.Extract(opentracing.HTTPHeaders, metadataReaderWriter{md})
|
|
}
|