From 4909a2fb70685c51583887e1a910781301dc6b83 Mon Sep 17 00:00:00 2001 From: Mikhail Mazurskiy Date: Mon, 12 Oct 2020 09:47:29 +1100 Subject: [PATCH] Support non-global tracing --- tracing/env_extractor.go | 7 +++---- tracing/env_extractor_option.go | 19 +++++++++++++++-- tracing/grpc/client_interceptors.go | 8 ++++---- tracing/grpc/server_interceptors.go | 8 ++++---- tracing/inbound_http.go | 10 ++------- tracing/inbound_http_options.go | 11 ++++++++++ tracing/initialization.go | 32 +++++++++++++++-------------- tracing/outbound_http.go | 7 +------ tracing/outbound_http_options.go | 11 ++++++++++ 9 files changed, 70 insertions(+), 43 deletions(-) diff --git a/tracing/env_extractor.go b/tracing/env_extractor.go index 2b92a8ab..33c7bd36 100644 --- a/tracing/env_extractor.go +++ b/tracing/env_extractor.go @@ -14,8 +14,7 @@ import ( // from the parent process. Returns a new context, and a defer'able function, which // should be called on process termination func ExtractFromEnv(ctx context.Context, opts ...ExtractFromEnvOption) (context.Context, func()) { - /* config not yet used */ applyExtractFromEnvOptions(opts) - tracer := opentracing.GlobalTracer() + config := applyExtractFromEnvOptions(opts) // Extract the Correlation-ID envMap := environAsMap(os.Environ()) @@ -25,7 +24,7 @@ func ExtractFromEnv(ctx context.Context, opts ...ExtractFromEnvOption) (context. } // Attempt to deserialize tracing identifiers - wireContext, err := tracer.Extract( + wireContext, err := config.tracer.Extract( opentracing.TextMap, opentracing.TextMapCarrier(envMap)) @@ -44,7 +43,7 @@ func ExtractFromEnv(ctx context.Context, opts ...ExtractFromEnvOption) (context. additionalStartSpanOpts = append(additionalStartSpanOpts, opentracing.Tag{Key: "correlation_id", Value: correlationID}) } - serverSpan := opentracing.StartSpan( + serverSpan := config.tracer.StartSpan( "execute", additionalStartSpanOpts..., ) diff --git a/tracing/env_extractor_option.go b/tracing/env_extractor_option.go index e9288c9d..275e0dc9 100644 --- a/tracing/env_extractor_option.go +++ b/tracing/env_extractor_option.go @@ -1,15 +1,30 @@ package tracing -type extractFromEnvConfig struct{} +import ( + opentracing "github.com/opentracing/opentracing-go" +) + +type extractFromEnvConfig struct { + tracer opentracing.Tracer +} // ExtractFromEnvOption will configure an environment injector type ExtractFromEnvOption func(*extractFromEnvConfig) func applyExtractFromEnvOptions(opts []ExtractFromEnvOption) extractFromEnvConfig { - config := extractFromEnvConfig{} + config := extractFromEnvConfig{ + tracer: opentracing.GlobalTracer(), + } for _, v := range opts { v(&config) } return config } + +// WithExtractFromEnvTracer sets a custom tracer to be used, otherwise the opentracing.GlobalTracer is used. +func WithExtractFromEnvTracer(tracer opentracing.Tracer) ExtractFromEnvOption { + return func(config *extractFromEnvConfig) { + config.tracer = tracer + } +} diff --git a/tracing/grpc/client_interceptors.go b/tracing/grpc/client_interceptors.go index e04d87e5..09355e3e 100644 --- a/tracing/grpc/client_interceptors.go +++ b/tracing/grpc/client_interceptors.go @@ -6,11 +6,11 @@ import ( ) // UnaryClientTracingInterceptor will create a unary client tracing interceptor -func UnaryClientTracingInterceptor() grpc.UnaryClientInterceptor { - return grpc_opentracing.UnaryClientInterceptor() +func UnaryClientTracingInterceptor(opts ...grpc_opentracing.Option) grpc.UnaryClientInterceptor { + return grpc_opentracing.UnaryClientInterceptor(opts...) } // StreamClientTracingInterceptor will create a streaming client tracing interceptor -func StreamClientTracingInterceptor() grpc.StreamClientInterceptor { - return grpc_opentracing.StreamClientInterceptor() +func StreamClientTracingInterceptor(opts ...grpc_opentracing.Option) grpc.StreamClientInterceptor { + return grpc_opentracing.StreamClientInterceptor(opts...) } diff --git a/tracing/grpc/server_interceptors.go b/tracing/grpc/server_interceptors.go index 4a077f2c..300a109b 100644 --- a/tracing/grpc/server_interceptors.go +++ b/tracing/grpc/server_interceptors.go @@ -6,11 +6,11 @@ import ( ) // UnaryServerTracingInterceptor will create a unary server tracing interceptor -func UnaryServerTracingInterceptor() grpc.UnaryServerInterceptor { - return grpc_opentracing.UnaryServerInterceptor() +func UnaryServerTracingInterceptor(opts ...grpc_opentracing.Option) grpc.UnaryServerInterceptor { + return grpc_opentracing.UnaryServerInterceptor(opts...) } // StreamServerTracingInterceptor will create a streaming server tracing interceptor -func StreamServerTracingInterceptor() grpc.StreamServerInterceptor { - return grpc_opentracing.StreamServerInterceptor() +func StreamServerTracingInterceptor(opts ...grpc_opentracing.Option) grpc.StreamServerInterceptor { + return grpc_opentracing.StreamServerInterceptor(opts...) } diff --git a/tracing/inbound_http.go b/tracing/inbound_http.go index c0145652..a90d1a51 100644 --- a/tracing/inbound_http.go +++ b/tracing/inbound_http.go @@ -13,13 +13,7 @@ func Handler(h http.Handler, opts ...HandlerOption) http.Handler { config := applyHandlerOptions(opts) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tracer := opentracing.GlobalTracer() - if tracer == nil { - h.ServeHTTP(w, r) - return - } - - wireContext, _ := tracer.Extract( + wireContext, _ := config.tracer.Extract( opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header)) @@ -34,7 +28,7 @@ func Handler(h http.Handler, opts ...HandlerOption) http.Handler { additionalStartSpanOpts = append(additionalStartSpanOpts, opentracing.Tag{Key: "correlation_id", Value: correlationID}) } - serverSpan := opentracing.StartSpan( + serverSpan := config.tracer.StartSpan( config.getOperationName(r), additionalStartSpanOpts..., ) diff --git a/tracing/inbound_http_options.go b/tracing/inbound_http_options.go index 0a0aff60..006364f0 100644 --- a/tracing/inbound_http_options.go +++ b/tracing/inbound_http_options.go @@ -3,6 +3,8 @@ package tracing import ( "fmt" "net/http" + + opentracing "github.com/opentracing/opentracing-go" ) // OperationNamer will return an operation name given an HTTP request @@ -11,6 +13,7 @@ type OperationNamer func(*http.Request) string // The configuration for InjectCorrelationID type handlerConfig struct { getOperationName OperationNamer + tracer opentracing.Tracer } // HandlerOption will configure a correlation handler @@ -22,6 +25,7 @@ func applyHandlerOptions(opts []HandlerOption) handlerConfig { // By default use `GET /x/y/z` for operation names return fmt.Sprintf("%s %s", req.Method, req.URL.Path) }, + tracer: opentracing.GlobalTracer(), } for _, v := range opts { v(&config) @@ -40,3 +44,10 @@ func WithRouteIdentifier(routeIdentifier string) HandlerOption { } } } + +// WithRoundTripperTracer sets a custom tracer to be used for this middleware, otherwise the opentracing.GlobalTracer is used. +func WithHandlerTracer(tracer opentracing.Tracer) HandlerOption { + return func(config *handlerConfig) { + config.tracer = tracer + } +} diff --git a/tracing/initialization.go b/tracing/initialization.go index 37a55407..a5473b94 100644 --- a/tracing/initialization.go +++ b/tracing/initialization.go @@ -1,6 +1,7 @@ package tracing import ( + "fmt" "io" opentracing "github.com/opentracing/opentracing-go" @@ -16,17 +17,27 @@ func (nopCloser) Close() error { return nil } // Initialize will initialize distributed tracing func Initialize(opts ...InitializationOption) io.Closer { + tracer, closer, err := ConstructTracer(opts...) + if err != nil { + log.WithError(err).Warn("Unable to construct tracer, skipping tracing configuration step") + return nopCloser{} + } + log.Info("Tracing enabled") + opentracing.SetGlobalTracer(tracer) + return closer +} + +func ConstructTracer(opts ...InitializationOption) (opentracing.Tracer, io.Closer, error) { config := applyInitializationOptions(opts) if config.connectionString == "" { // No opentracing connection has been set - return &nopCloser{} + return opentracing.NoopTracer{}, nopCloser{}, nil } driverName, options, err := connstr.Parse(config.connectionString) if err != nil { - log.WithError(err).Infoln("unable to parse connection") - return &nopCloser{} + return nil, nil, fmt.Errorf("unable to parse connection: %v", err) } if config.serviceName != "" { @@ -35,19 +46,10 @@ func Initialize(opts ...InitializationOption) io.Closer { tracer, closer, err := impl.New(driverName, options) if err != nil { - log.WithError(err).Warn("skipping tracing configuration step") - return &nopCloser{} + return nil, nil, err } - - if tracer == nil { - log.Warn("no tracer provided, tracing will be disabled") - } else { - log.Info("Tracing enabled") - opentracing.SetGlobalTracer(tracer) - } - if closer == nil { - return &nopCloser{} + closer = nopCloser{} } - return closer + return tracer, closer, nil } diff --git a/tracing/outbound_http.go b/tracing/outbound_http.go index afab8984..554c7325 100644 --- a/tracing/outbound_http.go +++ b/tracing/outbound_http.go @@ -17,11 +17,6 @@ type tracingRoundTripper struct { } func (c tracingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, e error) { - tracer := opentracing.GlobalTracer() - if tracer == nil { - return c.delegate.RoundTrip(req) - } - ctx := req.Context() var parentCtx opentracing.SpanContext @@ -31,7 +26,7 @@ func (c tracingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, e } // start a new Span to wrap HTTP request - span := opentracing.StartSpan( + span := c.config.tracer.StartSpan( c.config.getOperationName(req), opentracing.ChildOf(parentCtx), ) diff --git a/tracing/outbound_http_options.go b/tracing/outbound_http_options.go index 2777b1d3..a691ffec 100644 --- a/tracing/outbound_http_options.go +++ b/tracing/outbound_http_options.go @@ -3,11 +3,14 @@ package tracing import ( "fmt" "net/http" + + opentracing "github.com/opentracing/opentracing-go" ) // The configuration for InjectCorrelationID type roundTripperConfig struct { getOperationName OperationNamer + tracer opentracing.Tracer } // RoundTripperOption will configure a correlation handler @@ -19,6 +22,7 @@ func applyRoundTripperOptions(opts []RoundTripperOption) roundTripperConfig { // By default use `GET https://localhost` for operation names return fmt.Sprintf("%s %s://%s", req.Method, req.URL.Scheme, req.URL.Host) }, + tracer: opentracing.GlobalTracer(), } for _, v := range opts { v(&config) @@ -26,3 +30,10 @@ func applyRoundTripperOptions(opts []RoundTripperOption) roundTripperConfig { return config } + +// WithRoundTripperTracer sets a custom tracer to be used for this middleware, otherwise the opentracing.GlobalTracer is used. +func WithRoundTripperTracer(tracer opentracing.Tracer) RoundTripperOption { + return func(config *roundTripperConfig) { + config.tracer = tracer + } +} -- GitLab