From 8c352db36e83fc101698990e2ac1867845f78afd Mon Sep 17 00:00:00 2001 From: rbroggi Date: Sun, 14 Nov 2021 20:26:28 +0100 Subject: [PATCH 1/8] Issue 3362: * replacing the jaeger-client-go ot tracer implementation with the ot-otel bridge implementation Signed-off-by: rbroggi Signed-off-by: Yuri Shkuro --- examples/hotrod/cmd/customer.go | 3 +- examples/hotrod/cmd/driver.go | 3 +- examples/hotrod/cmd/frontend.go | 2 +- examples/hotrod/cmd/route.go | 2 +- examples/hotrod/pkg/log/factory.go | 14 ++--- examples/hotrod/pkg/tracing/init.go | 67 ++++++++------------- examples/hotrod/services/customer/server.go | 5 +- examples/hotrod/services/driver/redis.go | 5 +- examples/hotrod/services/driver/server.go | 5 +- 9 files changed, 42 insertions(+), 64 deletions(-) diff --git a/examples/hotrod/cmd/customer.go b/examples/hotrod/cmd/customer.go index ebdc5a71a42..a67f222c98a 100644 --- a/examples/hotrod/cmd/customer.go +++ b/examples/hotrod/cmd/customer.go @@ -37,8 +37,7 @@ var customerCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := customer.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(customerPort)), - tracing.Init("customer", metricsFactory, logger), - metricsFactory, + tracing.Init("customer", logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/driver.go b/examples/hotrod/cmd/driver.go index 5e0aa2b5231..ce46255d93a 100644 --- a/examples/hotrod/cmd/driver.go +++ b/examples/hotrod/cmd/driver.go @@ -37,8 +37,7 @@ var driverCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := driver.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(driverPort)), - tracing.Init("driver", metricsFactory, logger), - metricsFactory, + tracing.Init("driver", logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/frontend.go b/examples/hotrod/cmd/frontend.go index 273b15617e9..e4fc0d4ed6e 100644 --- a/examples/hotrod/cmd/frontend.go +++ b/examples/hotrod/cmd/frontend.go @@ -45,7 +45,7 @@ var frontendCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := frontend.NewServer( options, - tracing.Init("frontend", metricsFactory, logger), + tracing.Init("frontend", logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/route.go b/examples/hotrod/cmd/route.go index b962de6e609..638fc6861fe 100644 --- a/examples/hotrod/cmd/route.go +++ b/examples/hotrod/cmd/route.go @@ -37,7 +37,7 @@ var routeCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := route.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(routePort)), - tracing.Init("route", metricsFactory, logger), + tracing.Init("route", logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/pkg/log/factory.go b/examples/hotrod/pkg/log/factory.go index d32a98a97b4..2c85af90c5e 100644 --- a/examples/hotrod/pkg/log/factory.go +++ b/examples/hotrod/pkg/log/factory.go @@ -18,8 +18,8 @@ package log import ( "context" - "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-client-go" + ot "github.com/opentracing/opentracing-go" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -44,13 +44,13 @@ func (b Factory) Bg() Logger { // contains an OpenTracing span, all logging calls are also // echo-ed into the span. func (b Factory) For(ctx context.Context) Logger { - if span := opentracing.SpanFromContext(ctx); span != nil { - logger := spanLogger{span: span, logger: b.logger} + if otSpan := ot.SpanFromContext(ctx); otSpan != nil { + logger := spanLogger{span: otSpan, logger: b.logger} - if jaegerCtx, ok := span.Context().(jaeger.SpanContext); ok { + if otelSpan := trace.SpanFromContext(ctx); otelSpan != nil { logger.spanFields = []zapcore.Field{ - zap.String("trace_id", jaegerCtx.TraceID().String()), - zap.String("span_id", jaegerCtx.SpanID().String()), + zap.String("trace_id", otelSpan.SpanContext().TraceID().String()), + zap.String("span_id", otelSpan.SpanContext().SpanID().String()), } } diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index ac7eea460dc..f8ca10207a0 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -16,56 +16,39 @@ package tracing import ( - "fmt" - "time" - "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-client-go/config" - "github.com/uber/jaeger-client-go/rpcmetrics" - "github.com/uber/jaeger-lib/metrics" + "go.opentelemetry.io/otel" + otbridge "go.opentelemetry.io/otel/bridge/opentracing" + "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" ) -// Init creates a new instance of Jaeger tracer. -func Init(serviceName string, metricsFactory metrics.Factory, logger log.Factory) opentracing.Tracer { - cfg := &config.Configuration{ - Sampler: &config.SamplerConfig{}, - } - cfg.ServiceName = serviceName - cfg.Sampler.Type = "const" - cfg.Sampler.Param = 1 +// Init creates a new bridge opentrace tracer that sends spans to Jaeger. The +// bridge tracer is bind to an open telemetry tracer +func Init(serviceName string, logger log.Factory) opentracing.Tracer { - _, err := cfg.FromEnv() - if err != nil { - logger.Bg().Fatal("cannot parse Jaeger env vars", zap.Error(err)) - } - - // TODO(ys) a quick hack to ensure random generators get different seeds, which are based on current time. - time.Sleep(100 * time.Millisecond) - jaegerLogger := jaegerLoggerAdapter{logger.Bg()} - - metricsFactory = metricsFactory.Namespace(metrics.NSOptions{Name: serviceName, Tags: nil}) - tracer, _, err := cfg.NewTracer( - config.Logger(jaegerLogger), - config.Metrics(metricsFactory), - config.Observer(rpcmetrics.NewObserver(metricsFactory, rpcmetrics.DefaultNameNormalizer)), + // Create the Jaeger exporter + exp, err := jaeger.New( + jaeger.WithCollectorEndpoint( + jaeger.WithEndpoint("http://localhost:14268/api/traces"), + ), ) if err != nil { - logger.Bg().Fatal("cannot initialize Jaeger Tracer", zap.Error(err)) + logger.Bg().Fatal("cannot create Jaeger exporter", zap.Error(err)) } - return tracer -} - -type jaegerLoggerAdapter struct { - logger log.Logger -} - -func (l jaegerLoggerAdapter) Error(msg string) { - l.logger.Error(msg) -} - -func (l jaegerLoggerAdapter) Infof(msg string, args ...interface{}) { - l.logger.Info(fmt.Sprintf(msg, args...)) + tp := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exp), + sdktrace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String(serviceName), + )), + ) + otTracer, otelTracer := otbridge.NewTracerPair(tp.Tracer("")) + otel.SetTracerProvider(otelTracer) + return otTracer } diff --git a/examples/hotrod/services/customer/server.go b/examples/hotrod/services/customer/server.go index 264bfc74bf9..5294bb89c2a 100644 --- a/examples/hotrod/services/customer/server.go +++ b/examples/hotrod/services/customer/server.go @@ -20,7 +20,6 @@ import ( "net/http" "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-lib/metrics" "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/httperr" @@ -37,13 +36,13 @@ type Server struct { } // NewServer creates a new customer.Server -func NewServer(hostPort string, tracer opentracing.Tracer, metricsFactory metrics.Factory, logger log.Factory) *Server { +func NewServer(hostPort string, tracer opentracing.Tracer, logger log.Factory) *Server { return &Server{ hostPort: hostPort, tracer: tracer, logger: logger, database: newDatabase( - tracing.Init("mysql", metricsFactory, logger), + tracing.Init("mysql", logger), logger.With(zap.String("component", "mysql")), ), } diff --git a/examples/hotrod/services/driver/redis.go b/examples/hotrod/services/driver/redis.go index cefef66bbb6..fb610deab72 100644 --- a/examples/hotrod/services/driver/redis.go +++ b/examples/hotrod/services/driver/redis.go @@ -24,7 +24,6 @@ import ( "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go/ext" - "github.com/uber/jaeger-lib/metrics" "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/delay" @@ -40,9 +39,9 @@ type Redis struct { errorSimulator } -func newRedis(metricsFactory metrics.Factory, logger log.Factory) *Redis { +func newRedis(logger log.Factory) *Redis { return &Redis{ - tracer: tracing.Init("redis", metricsFactory, logger), + tracer: tracing.Init("redis", logger), logger: logger, } } diff --git a/examples/hotrod/services/driver/server.go b/examples/hotrod/services/driver/server.go index 99d325240d3..bc60cc910eb 100644 --- a/examples/hotrod/services/driver/server.go +++ b/examples/hotrod/services/driver/server.go @@ -21,7 +21,6 @@ import ( otgrpc "github.com/opentracing-contrib/go-grpc" "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-lib/metrics" "go.uber.org/zap" "google.golang.org/grpc" @@ -40,7 +39,7 @@ type Server struct { var _ DriverServiceServer = (*Server)(nil) // NewServer creates a new driver.Server -func NewServer(hostPort string, tracer opentracing.Tracer, metricsFactory metrics.Factory, logger log.Factory) *Server { +func NewServer(hostPort string, tracer opentracing.Tracer, logger log.Factory) *Server { server := grpc.NewServer(grpc.UnaryInterceptor( otgrpc.OpenTracingServerInterceptor(tracer)), grpc.StreamInterceptor( @@ -50,7 +49,7 @@ func NewServer(hostPort string, tracer opentracing.Tracer, metricsFactory metric tracer: tracer, logger: logger, server: server, - redis: newRedis(metricsFactory, logger), + redis: newRedis(logger), } } From 4e1495cbfeb2f64ccd7f14c2118241b9e29ac7c0 Mon Sep 17 00:00:00 2001 From: Rodrigo Broggi Date: Mon, 15 Nov 2021 09:47:04 +0100 Subject: [PATCH 2/8] Update examples/hotrod/pkg/tracing/init.go Co-authored-by: Yuri Shkuro Signed-off-by: rbroggi --- examples/hotrod/pkg/tracing/init.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index f8ca10207a0..bb2c7e603b3 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -28,8 +28,8 @@ import ( "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" ) -// Init creates a new bridge opentrace tracer that sends spans to Jaeger. The -// bridge tracer is bind to an open telemetry tracer +// Init initializes OpenTelemetry SDK and uses OTel-OpenTracing Bridge +// to return an OpenTracing-compatible tracer. func Init(serviceName string, logger log.Factory) opentracing.Tracer { // Create the Jaeger exporter From e19907deded67e266b647d971f86241af290f37e Mon Sep 17 00:00:00 2001 From: rbroggi Date: Sun, 21 Nov 2021 15:54:15 +0100 Subject: [PATCH 3/8] Issue 3362: * no need to globally register the otel tracer Signed-off-by: rbroggi Signed-off-by: rbroggi --- examples/hotrod/pkg/tracing/init.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index bb2c7e603b3..527d75e1a83 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -17,7 +17,6 @@ package tracing import ( "github.com/opentracing/opentracing-go" - "go.opentelemetry.io/otel" otbridge "go.opentelemetry.io/otel/bridge/opentracing" "go.opentelemetry.io/otel/exporters/jaeger" "go.opentelemetry.io/otel/sdk/resource" @@ -48,7 +47,6 @@ func Init(serviceName string, logger log.Factory) opentracing.Tracer { semconv.ServiceNameKey.String(serviceName), )), ) - otTracer, otelTracer := otbridge.NewTracerPair(tp.Tracer("")) - otel.SetTracerProvider(otelTracer) + otTracer, _ := otbridge.NewTracerPair(tp.Tracer("")) return otTracer } From 3e8f1e56d2ccec6ee3c63b4c0c6226f90af3228a Mon Sep 17 00:00:00 2001 From: Yuri Shkuro Date: Sat, 28 Jan 2023 13:41:35 -0500 Subject: [PATCH 4/8] go mod tidy Signed-off-by: Yuri Shkuro --- examples/hotrod/pkg/tracing/init.go | 1 + go.mod | 5 ++++- go.sum | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index 527d75e1a83..89b90a7572f 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -48,5 +48,6 @@ func Init(serviceName string, logger log.Factory) opentracing.Tracer { )), ) otTracer, _ := otbridge.NewTracerPair(tp.Tracer("")) + logger.Bg().Info("created OTEL->OT brige", zap.String("service-name", serviceName)) return otTracer } diff --git a/go.mod b/go.mod index 27bdd04536f..71bb6d190fd 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,11 @@ require ( go.opentelemetry.io/collector/receiver/otlpreceiver v0.70.0 go.opentelemetry.io/collector/semconv v0.70.0 go.opentelemetry.io/otel v1.11.2 + go.opentelemetry.io/otel/bridge/opentracing v1.11.2 + go.opentelemetry.io/otel/exporters/jaeger v1.11.2 go.opentelemetry.io/otel/metric v0.34.0 + go.opentelemetry.io/otel/sdk v1.11.2 + go.opentelemetry.io/otel/trace v1.11.2 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 go.uber.org/zap v1.24.0 @@ -146,7 +150,6 @@ require ( go.opentelemetry.io/collector/featuregate v0.70.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.37.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 // indirect - go.opentelemetry.io/otel/trace v1.11.2 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/text v0.6.0 // indirect diff --git a/go.sum b/go.sum index 41887c8d507..ee506742e10 100644 --- a/go.sum +++ b/go.sum @@ -728,10 +728,15 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 h1:yt2NKzK go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U= go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= +go.opentelemetry.io/otel/bridge/opentracing v1.11.2 h1:Wx51zQDSZDNo5wxMPhkPwzgpUZLQYYDtT41LCcl7opg= +go.opentelemetry.io/otel/bridge/opentracing v1.11.2/go.mod h1:kBrIQ2vqDIqtuS7Np7ALjmm8Tml7yxgsAGQwBhNvuU0= +go.opentelemetry.io/otel/exporters/jaeger v1.11.2 h1:ES8/j2+aB+3/BUw51ioxa50V9btN1eew/2J7N7n1tsE= +go.opentelemetry.io/otel/exporters/jaeger v1.11.2/go.mod h1:nwcF/DK4Hk0auZ/a5vw20uMsaJSXbzeeimhN5f9d0Lc= go.opentelemetry.io/otel/exporters/prometheus v0.34.0 h1:L5D+HxdaC/ORB47ribbTBbkXRZs9JzPjq0EoIOMWncM= go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= +go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= go.opentelemetry.io/otel/sdk/metric v0.34.0 h1:7ElxfQpXCFZlRTvVRTkcUvK8Gt5DC8QzmzsLsO2gdzo= go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= From 88f2bad084008f62e91ae7c352cc73ef75e9d7cf Mon Sep 17 00:00:00 2001 From: Yuri Shkuro Date: Sat, 28 Jan 2023 19:53:44 -0500 Subject: [PATCH 5/8] make it work Signed-off-by: Yuri Shkuro --- .gitignore | 3 ++ examples/hotrod/cmd/customer.go | 3 +- examples/hotrod/cmd/driver.go | 3 +- examples/hotrod/cmd/frontend.go | 2 +- examples/hotrod/cmd/root.go | 3 ++ examples/hotrod/cmd/route.go | 2 +- examples/hotrod/pkg/tracing/init.go | 49 +++++++++++++++++---- examples/hotrod/services/customer/server.go | 6 +-- examples/hotrod/services/driver/redis.go | 4 +- examples/hotrod/services/driver/server.go | 6 ++- go.mod | 9 +++- go.sum | 23 +++++++++- 12 files changed, 89 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 38127a8b5a7..95e336f38c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +go.work +go.work.sum + *.out *.test *.xml diff --git a/examples/hotrod/cmd/customer.go b/examples/hotrod/cmd/customer.go index a67f222c98a..c1f0f7a6d4c 100644 --- a/examples/hotrod/cmd/customer.go +++ b/examples/hotrod/cmd/customer.go @@ -23,7 +23,6 @@ import ( "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" - "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" "github.com/jaegertracing/jaeger/examples/hotrod/services/customer" ) @@ -37,7 +36,7 @@ var customerCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := customer.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(customerPort)), - tracing.Init("customer", logger), + otelExporter, logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/driver.go b/examples/hotrod/cmd/driver.go index ce46255d93a..6b5a80bd590 100644 --- a/examples/hotrod/cmd/driver.go +++ b/examples/hotrod/cmd/driver.go @@ -23,7 +23,6 @@ import ( "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" - "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" "github.com/jaegertracing/jaeger/examples/hotrod/services/driver" ) @@ -37,7 +36,7 @@ var driverCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := driver.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(driverPort)), - tracing.Init("driver", logger), + otelExporter, logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/frontend.go b/examples/hotrod/cmd/frontend.go index e4fc0d4ed6e..70a90acd40f 100644 --- a/examples/hotrod/cmd/frontend.go +++ b/examples/hotrod/cmd/frontend.go @@ -45,7 +45,7 @@ var frontendCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := frontend.NewServer( options, - tracing.Init("frontend", logger), + tracing.Init("frontend", otelExporter, logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/root.go b/examples/hotrod/cmd/root.go index 68b363ade08..83c75039c35 100644 --- a/examples/hotrod/cmd/root.go +++ b/examples/hotrod/cmd/root.go @@ -34,6 +34,7 @@ var ( metricsBackend string logger *zap.Logger metricsFactory metrics.Factory + otelExporter string // jaeger, otlp, stdout fixDBConnDelay time.Duration fixDBConnDisableMutex bool @@ -66,6 +67,8 @@ func Execute() { func init() { RootCmd.PersistentFlags().StringVarP(&metricsBackend, "metrics", "m", "expvar", "Metrics backend (expvar|prometheus)") + RootCmd.PersistentFlags().StringVarP(&otelExporter, "otel-exporter", "x", "jaeger", "OpenTelemetry exporter (jaeger|otlp|stdout)") + RootCmd.PersistentFlags().DurationVarP(&fixDBConnDelay, "fix-db-query-delay", "D", 300*time.Millisecond, "Average latency of MySQL DB query") RootCmd.PersistentFlags().BoolVarP(&fixDBConnDisableMutex, "fix-disable-db-conn-mutex", "M", false, "Disables the mutex guarding db connection") RootCmd.PersistentFlags().IntVarP(&fixRouteWorkerPoolSize, "fix-route-worker-pool-size", "W", 3, "Default worker pool size") diff --git a/examples/hotrod/cmd/route.go b/examples/hotrod/cmd/route.go index 638fc6861fe..90747a171be 100644 --- a/examples/hotrod/cmd/route.go +++ b/examples/hotrod/cmd/route.go @@ -37,7 +37,7 @@ var routeCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := route.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(routePort)), - tracing.Init("route", logger), + tracing.Init("route", otelExporter, logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index 89b90a7572f..cd563522540 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -16,9 +16,18 @@ package tracing import ( + "context" + "fmt" + "sync" + "github.com/opentracing/opentracing-go" + "go.opentelemetry.io/otel" otbridge "go.opentelemetry.io/otel/bridge/opentracing" "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.7.0" @@ -27,21 +36,22 @@ import ( "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" ) +var once sync.Once + // Init initializes OpenTelemetry SDK and uses OTel-OpenTracing Bridge // to return an OpenTracing-compatible tracer. -func Init(serviceName string, logger log.Factory) opentracing.Tracer { +func Init(serviceName string, exporterType string, logger log.Factory) opentracing.Tracer { + once.Do(func() { + otel.SetTextMapPropagator(propagation.TraceContext{}) + }) - // Create the Jaeger exporter - exp, err := jaeger.New( - jaeger.WithCollectorEndpoint( - jaeger.WithEndpoint("http://localhost:14268/api/traces"), - ), - ) + exp, err := createOtelExporter(exporterType) if err != nil { - logger.Bg().Fatal("cannot create Jaeger exporter", zap.Error(err)) + logger.Bg().Fatal("cannot create exporter", zap.String("exporterType", exporterType), zap.Error(err)) } + tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exp), + sdktrace.WithBatcher(exp, sdktrace.WithMaxExportBatchSize(1)), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(serviceName), @@ -51,3 +61,24 @@ func Init(serviceName string, logger log.Factory) opentracing.Tracer { logger.Bg().Info("created OTEL->OT brige", zap.String("service-name", serviceName)) return otTracer } + +func createOtelExporter(exporterType string) (sdktrace.SpanExporter, error) { + var exporter sdktrace.SpanExporter + var err error + switch exporterType { + case "jaeger": + exporter, err = jaeger.New( + jaeger.WithCollectorEndpoint(), + ) + case "otlp": + client := otlptracehttp.NewClient( + otlptracehttp.WithInsecure(), + ) + exporter, err = otlptrace.New(context.Background(), client) + case "stdout": + exporter, err = stdouttrace.New() + default: + err = fmt.Errorf("unrecognized exporter type %s", exporterType) + } + return exporter, err +} diff --git a/examples/hotrod/services/customer/server.go b/examples/hotrod/services/customer/server.go index 5294bb89c2a..27fd8c77bd9 100644 --- a/examples/hotrod/services/customer/server.go +++ b/examples/hotrod/services/customer/server.go @@ -36,13 +36,13 @@ type Server struct { } // NewServer creates a new customer.Server -func NewServer(hostPort string, tracer opentracing.Tracer, logger log.Factory) *Server { +func NewServer(hostPort string, otelExporter string, logger log.Factory) *Server { return &Server{ hostPort: hostPort, - tracer: tracer, + tracer: tracing.Init("customer", otelExporter, logger), logger: logger, database: newDatabase( - tracing.Init("mysql", logger), + tracing.Init("mysql", otelExporter, logger), logger.With(zap.String("component", "mysql")), ), } diff --git a/examples/hotrod/services/driver/redis.go b/examples/hotrod/services/driver/redis.go index fb610deab72..bc6eed92c6e 100644 --- a/examples/hotrod/services/driver/redis.go +++ b/examples/hotrod/services/driver/redis.go @@ -39,9 +39,9 @@ type Redis struct { errorSimulator } -func newRedis(logger log.Factory) *Redis { +func newRedis(otelExporter string, logger log.Factory) *Redis { return &Redis{ - tracer: tracing.Init("redis", logger), + tracer: tracing.Init("redis", otelExporter, logger), logger: logger, } } diff --git a/examples/hotrod/services/driver/server.go b/examples/hotrod/services/driver/server.go index bc60cc910eb..7311bc66caa 100644 --- a/examples/hotrod/services/driver/server.go +++ b/examples/hotrod/services/driver/server.go @@ -25,6 +25,7 @@ import ( "google.golang.org/grpc" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" + "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" ) // Server implements jaeger-demo-frontend service @@ -39,7 +40,8 @@ type Server struct { var _ DriverServiceServer = (*Server)(nil) // NewServer creates a new driver.Server -func NewServer(hostPort string, tracer opentracing.Tracer, logger log.Factory) *Server { +func NewServer(hostPort string, otelExporter string, logger log.Factory) *Server { + tracer := tracing.Init("driver", otelExporter, logger) server := grpc.NewServer(grpc.UnaryInterceptor( otgrpc.OpenTracingServerInterceptor(tracer)), grpc.StreamInterceptor( @@ -49,7 +51,7 @@ func NewServer(hostPort string, tracer opentracing.Tracer, logger log.Factory) * tracer: tracer, logger: logger, server: server, - redis: newRedis(logger), + redis: newRedis(otelExporter, logger), } } diff --git a/go.mod b/go.mod index 71bb6d190fd..be83adcfe12 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,9 @@ require ( go.opentelemetry.io/otel v1.11.2 go.opentelemetry.io/otel/bridge/opentracing v1.11.2 go.opentelemetry.io/otel/exporters/jaeger v1.11.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 go.opentelemetry.io/otel/metric v0.34.0 go.opentelemetry.io/otel/sdk v1.11.2 go.opentelemetry.io/otel/trace v1.11.2 @@ -74,6 +77,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect @@ -90,10 +94,11 @@ require ( github.com/go-openapi/analysis v0.21.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/flatbuffers v1.12.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -150,6 +155,8 @@ require ( go.opentelemetry.io/collector/featuregate v0.70.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.37.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/text v0.6.0 // indirect diff --git a/go.sum b/go.sum index ee506742e10..d15ec317d8e 100644 --- a/go.sum +++ b/go.sum @@ -94,6 +94,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bsm/sarama-cluster v2.1.13+incompatible h1:bqU3gMJbWZVxLZ9PGWVKP05yOmFXUlfw61RBwuE3PYU= github.com/bsm/sarama-cluster v2.1.13+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -108,6 +110,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -147,6 +150,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -253,8 +257,9 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -339,6 +344,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= @@ -732,7 +739,15 @@ go.opentelemetry.io/otel/bridge/opentracing v1.11.2 h1:Wx51zQDSZDNo5wxMPhkPwzgpU go.opentelemetry.io/otel/bridge/opentracing v1.11.2/go.mod h1:kBrIQ2vqDIqtuS7Np7ALjmm8Tml7yxgsAGQwBhNvuU0= go.opentelemetry.io/otel/exporters/jaeger v1.11.2 h1:ES8/j2+aB+3/BUw51ioxa50V9btN1eew/2J7N7n1tsE= go.opentelemetry.io/otel/exporters/jaeger v1.11.2/go.mod h1:nwcF/DK4Hk0auZ/a5vw20uMsaJSXbzeeimhN5f9d0Lc= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 h1:htgM8vZIF8oPSCxa341e3IZ4yr/sKxgu8KZYllByiVY= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2/go.mod h1:rqbht/LlhVBgn5+k3M5QK96K5Xb0DvXpMJ5SFQpY6uw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2 h1:fqR1kli93643au1RKo0Uma3d2aPQKT+WBKfTSBaKbOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2/go.mod h1:5Qn6qvgkMsLDX+sYK64rHb1FPhpn0UtxF+ouX1uhyJE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2 h1:Us8tbCmuN16zAnK5TC69AtODLycKbwnskQzaB6DfFhc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2/go.mod h1:GZWSQQky8AgdJj50r1KJm8oiQiIPaAX7uZCFQX9GzC8= go.opentelemetry.io/otel/exporters/prometheus v0.34.0 h1:L5D+HxdaC/ORB47ribbTBbkXRZs9JzPjq0EoIOMWncM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2 h1:BhEVgvuE1NWLLuMLvC6sif791F45KFHi5GhOs1KunZU= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.2/go.mod h1:bx//lU66dPzNT+Y0hHA12ciKoMOH9iixEwCqC1OeQWQ= go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= @@ -741,6 +756,8 @@ go.opentelemetry.io/otel/sdk/metric v0.34.0 h1:7ElxfQpXCFZlRTvVRTkcUvK8Gt5DC8Qzm go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= @@ -873,6 +890,7 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1116,6 +1134,7 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1140,6 +1159,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.52.1 h1:2NpOPk5g5Xtb0qebIEs7hNIa++PdtZLo2AQUpc1YnSU= google.golang.org/grpc v1.52.1/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= @@ -1155,6 +1175,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= From 91816c6196f20782d4ee1cfcd087596db4daf233 Mon Sep 17 00:00:00 2001 From: Yuri Shkuro Date: Sun, 29 Jan 2023 02:24:07 -0500 Subject: [PATCH 6/8] add favicon Signed-off-by: Yuri Shkuro --- .../services/frontend/web_assets/favicon.ico | Bin 0 -> 15406 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/hotrod/services/frontend/web_assets/favicon.ico diff --git a/examples/hotrod/services/frontend/web_assets/favicon.ico b/examples/hotrod/services/frontend/web_assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..caa965150170309a0f70e5ec286a2fe7e7ea5b65 GIT binary patch literal 15406 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 Date: Sun, 29 Jan 2023 03:19:50 -0500 Subject: [PATCH 7/8] implement rpc metrics Signed-off-by: Yuri Shkuro --- examples/hotrod/cmd/customer.go | 1 + examples/hotrod/cmd/driver.go | 1 + examples/hotrod/cmd/frontend.go | 2 +- examples/hotrod/cmd/root.go | 10 +- examples/hotrod/cmd/route.go | 2 +- examples/hotrod/pkg/tracing/init.go | 12 +- .../hotrod/pkg/tracing/rpcmetrics/README.md | 3 + .../pkg/tracing/rpcmetrics/endpoints.go | 63 +++++++ .../pkg/tracing/rpcmetrics/endpoints_test.go | 44 +++++ .../hotrod/pkg/tracing/rpcmetrics/metrics.go | 125 ++++++++++++++ .../pkg/tracing/rpcmetrics/metrics_test.go | 61 +++++++ .../pkg/tracing/rpcmetrics/normalizer.go | 101 +++++++++++ .../pkg/tracing/rpcmetrics/normalizer_test.go | 35 ++++ .../hotrod/pkg/tracing/rpcmetrics/observer.go | 92 ++++++++++ .../pkg/tracing/rpcmetrics/observer_test.go | 163 ++++++++++++++++++ examples/hotrod/services/customer/server.go | 7 +- examples/hotrod/services/driver/redis.go | 5 +- examples/hotrod/services/driver/server.go | 7 +- internal/metricstest/metricstest.go | 2 +- 19 files changed, 717 insertions(+), 19 deletions(-) create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/README.md create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/endpoints.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/endpoints_test.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/metrics.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/normalizer.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/normalizer_test.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/observer.go create mode 100644 examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go diff --git a/examples/hotrod/cmd/customer.go b/examples/hotrod/cmd/customer.go index c1f0f7a6d4c..56f77bfec44 100644 --- a/examples/hotrod/cmd/customer.go +++ b/examples/hotrod/cmd/customer.go @@ -37,6 +37,7 @@ var customerCmd = &cobra.Command{ server := customer.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(customerPort)), otelExporter, + metricsFactory, logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/driver.go b/examples/hotrod/cmd/driver.go index 6b5a80bd590..ac1bf5ae65a 100644 --- a/examples/hotrod/cmd/driver.go +++ b/examples/hotrod/cmd/driver.go @@ -37,6 +37,7 @@ var driverCmd = &cobra.Command{ server := driver.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(driverPort)), otelExporter, + metricsFactory, logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/frontend.go b/examples/hotrod/cmd/frontend.go index 70a90acd40f..edf44501f64 100644 --- a/examples/hotrod/cmd/frontend.go +++ b/examples/hotrod/cmd/frontend.go @@ -45,7 +45,7 @@ var frontendCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := frontend.NewServer( options, - tracing.Init("frontend", otelExporter, logger), + tracing.Init("frontend", otelExporter, metricsFactory, logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/cmd/root.go b/examples/hotrod/cmd/root.go index 83c75039c35..81d5ec86f3a 100644 --- a/examples/hotrod/cmd/root.go +++ b/examples/hotrod/cmd/root.go @@ -21,13 +21,13 @@ import ( "time" "github.com/spf13/cobra" - "github.com/uber/jaeger-lib/metrics" - jexpvar "github.com/uber/jaeger-lib/metrics/expvar" - jprom "github.com/uber/jaeger-lib/metrics/prometheus" "go.uber.org/zap" "go.uber.org/zap/zapcore" "github.com/jaegertracing/jaeger/examples/hotrod/services/config" + "github.com/jaegertracing/jaeger/internal/metrics/expvar" + "github.com/jaegertracing/jaeger/internal/metrics/prometheus" + "github.com/jaegertracing/jaeger/pkg/metrics" ) var ( @@ -95,10 +95,10 @@ func init() { func onInitialize() { switch metricsBackend { case "expvar": - metricsFactory = jexpvar.NewFactory(10) // 10 buckets for histograms + metricsFactory = expvar.NewFactory(10) // 10 buckets for histograms logger.Info("Using expvar as metrics backend") case "prometheus": - metricsFactory = jprom.New().Namespace(metrics.NSOptions{Name: "hotrod", Tags: nil}) + metricsFactory = prometheus.New().Namespace(metrics.NSOptions{Name: "hotrod", Tags: nil}) logger.Info("Using Prometheus as metrics backend") default: logger.Fatal("unsupported metrics backend " + metricsBackend) diff --git a/examples/hotrod/cmd/route.go b/examples/hotrod/cmd/route.go index 90747a171be..ce54159f17c 100644 --- a/examples/hotrod/cmd/route.go +++ b/examples/hotrod/cmd/route.go @@ -37,7 +37,7 @@ var routeCmd = &cobra.Command{ logger := log.NewFactory(zapLogger) server := route.NewServer( net.JoinHostPort("0.0.0.0", strconv.Itoa(routePort)), - tracing.Init("route", otelExporter, logger), + tracing.Init("route", otelExporter, metricsFactory, logger), logger, ) return logError(zapLogger, server.Run()) diff --git a/examples/hotrod/pkg/tracing/init.go b/examples/hotrod/pkg/tracing/init.go index cd563522540..eb201e9d6d1 100644 --- a/examples/hotrod/pkg/tracing/init.go +++ b/examples/hotrod/pkg/tracing/init.go @@ -34,13 +34,15 @@ import ( "go.uber.org/zap" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" + "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing/rpcmetrics" + "github.com/jaegertracing/jaeger/pkg/metrics" ) var once sync.Once // Init initializes OpenTelemetry SDK and uses OTel-OpenTracing Bridge // to return an OpenTracing-compatible tracer. -func Init(serviceName string, exporterType string, logger log.Factory) opentracing.Tracer { +func Init(serviceName string, exporterType string, metricsFactory metrics.Factory, logger log.Factory) opentracing.Tracer { once.Do(func() { otel.SetTextMapPropagator(propagation.TraceContext{}) }) @@ -49,9 +51,13 @@ func Init(serviceName string, exporterType string, logger log.Factory) opentraci if err != nil { logger.Bg().Fatal("cannot create exporter", zap.String("exporterType", exporterType), zap.Error(err)) } + logger.Bg().Info("using " + exporterType + " trace exporter") + + rpcmetricsObserver := rpcmetrics.NewObserver(metricsFactory, rpcmetrics.DefaultNameNormalizer) tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exp, sdktrace.WithMaxExportBatchSize(1)), + sdktrace.WithBatcher(exp), + sdktrace.WithSpanProcessor(rpcmetricsObserver), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(serviceName), @@ -78,7 +84,7 @@ func createOtelExporter(exporterType string) (sdktrace.SpanExporter, error) { case "stdout": exporter, err = stdouttrace.New() default: - err = fmt.Errorf("unrecognized exporter type %s", exporterType) + return nil, fmt.Errorf("unrecognized exporter type %s", exporterType) } return exporter, err } diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/README.md b/examples/hotrod/pkg/tracing/rpcmetrics/README.md new file mode 100644 index 00000000000..34126b693cb --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/README.md @@ -0,0 +1,3 @@ +Package rpcmetrics implements an OpenTelemetry SpanProcessor that can be used to emit RPC metrics. + +This package is copied from jaeger-client-go and adapted to work with OpenTelemtery SDK. diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/endpoints.go b/examples/hotrod/pkg/tracing/rpcmetrics/endpoints.go new file mode 100644 index 00000000000..7ca73bfa18b --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/endpoints.go @@ -0,0 +1,63 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import "sync" + +// normalizedEndpoints is a cache for endpointName -> safeName mappings. +type normalizedEndpoints struct { + names map[string]string + maxSize int + normalizer NameNormalizer + mux sync.RWMutex +} + +func newNormalizedEndpoints(maxSize int, normalizer NameNormalizer) *normalizedEndpoints { + return &normalizedEndpoints{ + maxSize: maxSize, + normalizer: normalizer, + names: make(map[string]string, maxSize), + } +} + +// normalize looks up the name in the cache, if not found it uses normalizer +// to convert the name to a safe name. If called with more than maxSize unique +// names it returns "" for all other names beyond those already cached. +func (n *normalizedEndpoints) normalize(name string) string { + n.mux.RLock() + norm, ok := n.names[name] + l := len(n.names) + n.mux.RUnlock() + if ok { + return norm + } + if l >= n.maxSize { + return "" + } + return n.normalizeWithLock(name) +} + +func (n *normalizedEndpoints) normalizeWithLock(name string) string { + norm := n.normalizer.Normalize(name) + n.mux.Lock() + defer n.mux.Unlock() + // cache may have grown while we were not holding the lock + if len(n.names) >= n.maxSize { + return "" + } + n.names[name] = norm + return norm +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/endpoints_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/endpoints_test.go new file mode 100644 index 00000000000..fc1f84f6c19 --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/endpoints_test.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNormalizedEndpoints(t *testing.T) { + n := newNormalizedEndpoints(1, DefaultNameNormalizer) + + assertLen := func(l int) { + n.mux.RLock() + defer n.mux.RUnlock() + assert.Len(t, n.names, l) + } + + assert.Equal(t, "ab_cd", n.normalize("ab^cd"), "one translation") + assert.Equal(t, "ab_cd", n.normalize("ab^cd"), "cache hit") + assertLen(1) + assert.Equal(t, "", n.normalize("xys"), "cache overflow") + assertLen(1) +} + +func TestNormalizedEndpointsDoubleLocking(t *testing.T) { + n := newNormalizedEndpoints(1, DefaultNameNormalizer) + assert.Equal(t, "ab_cd", n.normalize("ab^cd"), "fill out the cache") + assert.Equal(t, "", n.normalizeWithLock("xys"), "cache overflow") +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/metrics.go b/examples/hotrod/pkg/tracing/rpcmetrics/metrics.go new file mode 100644 index 00000000000..83739876c5c --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/metrics.go @@ -0,0 +1,125 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "sync" + + "github.com/jaegertracing/jaeger/pkg/metrics" +) + +const ( + otherEndpointsPlaceholder = "other" + endpointNameMetricTag = "endpoint" +) + +// Metrics is a collection of metrics for an endpoint describing +// throughput, success, errors, and performance. +type Metrics struct { + // RequestCountSuccess is a counter of the total number of successes. + RequestCountSuccess metrics.Counter `metric:"requests" tags:"error=false"` + + // RequestCountFailures is a counter of the number of times any failure has been observed. + RequestCountFailures metrics.Counter `metric:"requests" tags:"error=true"` + + // RequestLatencySuccess is a latency histogram of successful requests. + RequestLatencySuccess metrics.Timer `metric:"request_latency" tags:"error=false"` + + // RequestLatencyFailures is a latency histogram of failed requests. + RequestLatencyFailures metrics.Timer `metric:"request_latency" tags:"error=true"` + + // HTTPStatusCode2xx is a counter of the total number of requests with HTTP status code 200-299 + HTTPStatusCode2xx metrics.Counter `metric:"http_requests" tags:"status_code=2xx"` + + // HTTPStatusCode3xx is a counter of the total number of requests with HTTP status code 300-399 + HTTPStatusCode3xx metrics.Counter `metric:"http_requests" tags:"status_code=3xx"` + + // HTTPStatusCode4xx is a counter of the total number of requests with HTTP status code 400-499 + HTTPStatusCode4xx metrics.Counter `metric:"http_requests" tags:"status_code=4xx"` + + // HTTPStatusCode5xx is a counter of the total number of requests with HTTP status code 500-599 + HTTPStatusCode5xx metrics.Counter `metric:"http_requests" tags:"status_code=5xx"` +} + +func (m *Metrics) recordHTTPStatusCode(statusCode int64) { + if statusCode >= 200 && statusCode < 300 { + m.HTTPStatusCode2xx.Inc(1) + } else if statusCode >= 300 && statusCode < 400 { + m.HTTPStatusCode3xx.Inc(1) + } else if statusCode >= 400 && statusCode < 500 { + m.HTTPStatusCode4xx.Inc(1) + } else if statusCode >= 500 && statusCode < 600 { + m.HTTPStatusCode5xx.Inc(1) + } +} + +// MetricsByEndpoint is a registry/cache of metrics for each unique endpoint name. +// Only maxNumberOfEndpoints Metrics are stored, all other endpoint names are mapped +// to a generic endpoint name "other". +type MetricsByEndpoint struct { + metricsFactory metrics.Factory + endpoints *normalizedEndpoints + metricsByEndpoint map[string]*Metrics + mux sync.RWMutex +} + +func newMetricsByEndpoint( + metricsFactory metrics.Factory, + normalizer NameNormalizer, + maxNumberOfEndpoints int, +) *MetricsByEndpoint { + return &MetricsByEndpoint{ + metricsFactory: metricsFactory, + endpoints: newNormalizedEndpoints(maxNumberOfEndpoints, normalizer), + metricsByEndpoint: make(map[string]*Metrics, maxNumberOfEndpoints+1), // +1 for "other" + } +} + +func (m *MetricsByEndpoint) get(endpoint string) *Metrics { + safeName := m.endpoints.normalize(endpoint) + if safeName == "" { + safeName = otherEndpointsPlaceholder + } + m.mux.RLock() + met := m.metricsByEndpoint[safeName] + m.mux.RUnlock() + if met != nil { + return met + } + + return m.getWithWriteLock(safeName) +} + +// split to make easier to test +func (m *MetricsByEndpoint) getWithWriteLock(safeName string) *Metrics { + m.mux.Lock() + defer m.mux.Unlock() + + // it is possible that the name has been already registered after we released + // the read lock and before we grabbed the write lock, so check for that. + if met, ok := m.metricsByEndpoint[safeName]; ok { + return met + } + + // it would be nice to create the struct before locking, since Init() is somewhat + // expensive, however some metrics backends (e.g. expvar) may not like duplicate metrics. + met := &Metrics{} + tags := map[string]string{endpointNameMetricTag: safeName} + metrics.Init(met, m.metricsFactory, tags) + + m.metricsByEndpoint[safeName] = met + return met +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go new file mode 100644 index 00000000000..3268c9830fc --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go @@ -0,0 +1,61 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "testing" + + "github.com/jaegertracing/jaeger/internal/metricstest" + "github.com/stretchr/testify/assert" +) + +// E.g. tags("key", "value", "key", "value") +func tags(kv ...string) map[string]string { + m := make(map[string]string) + for i := 0; i < len(kv)-1; i += 2 { + m[kv[i]] = kv[i+1] + } + return m +} + +func endpointTags(endpoint string, kv ...string) map[string]string { + return tags(append([]string{"endpoint", endpoint}, kv...)...) +} + +func TestMetricsByEndpoint(t *testing.T) { + met := metricstest.NewFactory(0) + mbe := newMetricsByEndpoint(met, DefaultNameNormalizer, 2) + + m1 := mbe.get("abc1") + m2 := mbe.get("abc1") // from cache + m2a := mbe.getWithWriteLock("abc1") // from cache in double-checked lock + assert.Equal(t, m1, m2) + assert.Equal(t, m1, m2a) + + m3 := mbe.get("abc3") + m4 := mbe.get("overflow") + m5 := mbe.get("overflow2") + + for _, m := range []*Metrics{m1, m2, m2a, m3, m4, m5} { + m.RequestCountSuccess.Inc(1) + } + + met.AssertCounterMetrics(t, + metricstest.ExpectedMetric{Name: "requests", Tags: endpointTags("abc1", "error", "false"), Value: 3}, + metricstest.ExpectedMetric{Name: "requests", Tags: endpointTags("abc3", "error", "false"), Value: 1}, + metricstest.ExpectedMetric{Name: "requests", Tags: endpointTags("other", "error", "false"), Value: 2}, + ) +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/normalizer.go b/examples/hotrod/pkg/tracing/rpcmetrics/normalizer.go new file mode 100644 index 00000000000..01f5bcd72ad --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/normalizer.go @@ -0,0 +1,101 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +// NameNormalizer is used to convert the endpoint names to strings +// that can be safely used as tags in the metrics. +type NameNormalizer interface { + Normalize(name string) string +} + +// DefaultNameNormalizer converts endpoint names so that they contain only characters +// from the safe charset [a-zA-Z0-9./_]. All other characters are replaced with '_'. +var DefaultNameNormalizer = &SimpleNameNormalizer{ + SafeSets: []SafeCharacterSet{ + &Range{From: 'a', To: 'z'}, + &Range{From: 'A', To: 'Z'}, + &Range{From: '0', To: '9'}, + &Char{'_'}, + &Char{'/'}, + &Char{'.'}, + }, + Replacement: '_', +} + +// SimpleNameNormalizer uses a set of safe character sets. +type SimpleNameNormalizer struct { + SafeSets []SafeCharacterSet + Replacement byte +} + +// SafeCharacterSet determines if the given character is "safe" +type SafeCharacterSet interface { + IsSafe(c byte) bool +} + +// Range implements SafeCharacterSet +type Range struct { + From, To byte +} + +// IsSafe implements SafeCharacterSet +func (r *Range) IsSafe(c byte) bool { + return c >= r.From && c <= r.To +} + +// Char implements SafeCharacterSet +type Char struct { + Val byte +} + +// IsSafe implements SafeCharacterSet +func (ch *Char) IsSafe(c byte) bool { + return c == ch.Val +} + +// Normalize checks each character in the string against SafeSets, +// and if it's not safe substitutes it with Replacement. +func (n *SimpleNameNormalizer) Normalize(name string) string { + var retMe []byte + nameBytes := []byte(name) + for i, b := range nameBytes { + if n.safeByte(b) { + if retMe != nil { + retMe[i] = b + } + } else { + if retMe == nil { + retMe = make([]byte, len(nameBytes)) + copy(retMe[0:i], nameBytes[0:i]) + } + retMe[i] = n.Replacement + } + } + if retMe == nil { + return name + } + return string(retMe) +} + +// safeByte checks if b against all safe charsets. +func (n *SimpleNameNormalizer) safeByte(b byte) bool { + for i := range n.SafeSets { + if n.SafeSets[i].IsSafe(b) { + return true + } + } + return false +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/normalizer_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/normalizer_test.go new file mode 100644 index 00000000000..dac1ff7ab39 --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/normalizer_test.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSimpleNameNormalizer(t *testing.T) { + n := &SimpleNameNormalizer{ + SafeSets: []SafeCharacterSet{ + &Range{From: 'a', To: 'z'}, + &Char{'-'}, + }, + Replacement: '-', + } + assert.Equal(t, "ab-cd", n.Normalize("ab-cd"), "all valid") + assert.Equal(t, "ab-cd", n.Normalize("ab.cd"), "single mismatch") + assert.Equal(t, "a--cd", n.Normalize("aB-cd"), "range letter mismatch") +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/observer.go b/examples/hotrod/pkg/tracing/rpcmetrics/observer.go new file mode 100644 index 00000000000..383660e1c81 --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/observer.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "context" + "strconv" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" + "go.opentelemetry.io/otel/trace" + + "github.com/jaegertracing/jaeger/pkg/metrics" +) + +const defaultMaxNumberOfEndpoints = 200 + +var _ sdktrace.SpanProcessor = (*Observer)(nil) + +// Observer is an observer that can emit RPC metrics. +type Observer struct { + metricsByEndpoint *MetricsByEndpoint +} + +// NewObserver creates a new observer that can emit RPC metrics. +func NewObserver(metricsFactory metrics.Factory, normalizer NameNormalizer) *Observer { + return &Observer{ + metricsByEndpoint: newMetricsByEndpoint( + metricsFactory, + normalizer, + defaultMaxNumberOfEndpoints, + ), + } +} + +func (o *Observer) OnStart(parent context.Context, s sdktrace.ReadWriteSpan) {} + +func (o *Observer) OnEnd(sp sdktrace.ReadOnlySpan) { + operationName := sp.Name() + if operationName == "" { + return + } + if sp.SpanKind() != trace.SpanKindServer { + return + } + + mets := o.metricsByEndpoint.get(operationName) + latency := sp.EndTime().Sub(sp.StartTime()) + + if status := sp.Status(); status.Code == codes.Error { + mets.RequestCountFailures.Inc(1) + mets.RequestLatencyFailures.Record(latency) + } else { + mets.RequestCountSuccess.Inc(1) + mets.RequestLatencySuccess.Record(latency) + } + for _, attr := range sp.Attributes() { + if string(attr.Key) == string(semconv.HTTPStatusCodeKey) { + if attr.Value.Type() == attribute.INT64 { + mets.recordHTTPStatusCode(attr.Value.AsInt64()) + } else if attr.Value.Type() == attribute.STRING { + s := attr.Value.AsString() + if n, err := strconv.Atoi(s); err == nil { + mets.recordHTTPStatusCode(int64(n)) + } + } + } + } +} + +func (o *Observer) Shutdown(ctx context.Context) error { + return nil +} + +func (o *Observer) ForceFlush(ctx context.Context) error { + return nil +} diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go new file mode 100644 index 00000000000..4dfb65470bb --- /dev/null +++ b/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go @@ -0,0 +1,163 @@ +// Copyright (c) 2023 The Jaeger Authors. +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpcmetrics + +import ( + "fmt" + "testing" + "time" + + opentracing "github.com/opentracing/opentracing-go" + "github.com/stretchr/testify/assert" + otbridge "go.opentelemetry.io/otel/bridge/opentracing" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" + + "github.com/opentracing/opentracing-go/ext" + + u "github.com/jaegertracing/jaeger/internal/metricstest" +) + +type testTracer struct { + metrics *u.Factory + tracer opentracing.Tracer +} + +func withTestTracer(runTest func(tt *testTracer)) { + metrics := u.NewFactory(time.Minute) + observer := NewObserver(metrics, DefaultNameNormalizer) + + tp := sdktrace.NewTracerProvider( + sdktrace.WithSpanProcessor(observer), + sdktrace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("test"), + )), + ) + tracer, _ := otbridge.NewTracerPair(tp.Tracer("")) + runTest(&testTracer{ + metrics: metrics, + tracer: tracer, + }) +} + +func TestObserver(t *testing.T) { + withTestTracer(func(testTracer *testTracer) { + ts := time.Now() + finishOptions := opentracing.FinishOptions{ + FinishTime: ts.Add(50 * time.Millisecond), + } + + testCases := []struct { + name string + tag opentracing.Tag + opNameOverride string + err bool + }{ + {name: "local-span", tag: opentracing.Tag{Key: "x", Value: "y"}}, + {name: "get-user", tag: ext.SpanKindRPCServer}, + {name: "get-user", tag: ext.SpanKindRPCServer, opNameOverride: "get-user-override"}, + {name: "get-user", tag: ext.SpanKindRPCServer, err: true}, + {name: "get-user-client", tag: ext.SpanKindRPCClient}, + } + + for _, testCase := range testCases { + span := testTracer.tracer.StartSpan( + testCase.name, + testCase.tag, + opentracing.StartTime(ts), + ) + if testCase.opNameOverride != "" { + span.SetOperationName(testCase.opNameOverride) + } + if testCase.err { + ext.Error.Set(span, true) + } + span.FinishWithOptions(finishOptions) + } + + testTracer.metrics.AssertCounterMetrics(t, + u.ExpectedMetric{Name: "requests", Tags: endpointTags("local_span", "error", "false"), Value: 0}, + u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user", "error", "false"), Value: 1}, + u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user", "error", "true"), Value: 1}, + u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user_override", "error", "false"), Value: 1}, + u.ExpectedMetric{Name: "requests", Tags: endpointTags("get_user_client", "error", "false"), Value: 0}, + ) + // TODO something wrong with string generation, .P99 should not be appended to the tag + // as a result we cannot use u.AssertGaugeMetrics + _, g := testTracer.metrics.Snapshot() + assert.EqualValues(t, 51, g["request_latency|endpoint=get_user|error=false.P99"]) + assert.EqualValues(t, 51, g["request_latency|endpoint=get_user|error=true.P99"]) + }) +} + +func TestTags(t *testing.T) { + type tagTestCase struct { + key string + variant string + value interface{} + metrics []u.ExpectedMetric + } + + testCases := []tagTestCase{ + {key: "something", value: 42, metrics: []u.ExpectedMetric{ + {Name: "requests", Value: 1, Tags: tags("error", "false")}, + }}, + {key: "error", value: true, metrics: []u.ExpectedMetric{ + {Name: "requests", Value: 1, Tags: tags("error", "true")}, + }}, + // OTEL bridge does not interpret string "true" as error status + // {key: "error", value: "true", variant: "string", metrics: []u.ExpectedMetric{ + // {Name: "requests", Value: 1, Tags: tags("error", "true")}, + // }}, + } + + for i := 200; i <= 500; i += 100 { + status_codes := []struct { + value interface{} + variant string + }{ + {value: i}, + {value: uint16(i), variant: "uint16"}, + {value: fmt.Sprintf("%d", i), variant: "string"}, + } + for _, v := range status_codes { + testCases = append(testCases, tagTestCase{ + key: "http.status_code", + value: v.value, + variant: v.variant, + metrics: []u.ExpectedMetric{ + {Name: "http_requests", Value: 1, Tags: tags("status_code", fmt.Sprintf("%dxx", i/100))}, + }, + }) + } + } + + for _, testCase := range testCases { + for i := range testCase.metrics { + testCase.metrics[i].Tags["endpoint"] = "span" + } + t.Run(fmt.Sprintf("%s-%v-%s", testCase.key, testCase.value, testCase.variant), func(t *testing.T) { + withTestTracer(func(testTracer *testTracer) { + span := testTracer.tracer.StartSpan("span", ext.SpanKindRPCServer) + span.SetTag(testCase.key, testCase.value) + span.Finish() + testTracer.metrics.AssertCounterMetrics(t, testCase.metrics...) + }) + }) + } +} diff --git a/examples/hotrod/services/customer/server.go b/examples/hotrod/services/customer/server.go index 27fd8c77bd9..f35a15c36a6 100644 --- a/examples/hotrod/services/customer/server.go +++ b/examples/hotrod/services/customer/server.go @@ -25,6 +25,7 @@ import ( "github.com/jaegertracing/jaeger/examples/hotrod/pkg/httperr" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" + "github.com/jaegertracing/jaeger/pkg/metrics" ) // Server implements Customer service @@ -36,13 +37,13 @@ type Server struct { } // NewServer creates a new customer.Server -func NewServer(hostPort string, otelExporter string, logger log.Factory) *Server { +func NewServer(hostPort string, otelExporter string, metricsFactory metrics.Factory, logger log.Factory) *Server { return &Server{ hostPort: hostPort, - tracer: tracing.Init("customer", otelExporter, logger), + tracer: tracing.Init("customer", otelExporter, metricsFactory, logger), logger: logger, database: newDatabase( - tracing.Init("mysql", otelExporter, logger), + tracing.Init("mysql", otelExporter, metricsFactory, logger), logger.With(zap.String("component", "mysql")), ), } diff --git a/examples/hotrod/services/driver/redis.go b/examples/hotrod/services/driver/redis.go index bc6eed92c6e..ae29785182b 100644 --- a/examples/hotrod/services/driver/redis.go +++ b/examples/hotrod/services/driver/redis.go @@ -30,6 +30,7 @@ import ( "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" "github.com/jaegertracing/jaeger/examples/hotrod/services/config" + "github.com/jaegertracing/jaeger/pkg/metrics" ) // Redis is a simulator of remote Redis cache @@ -39,9 +40,9 @@ type Redis struct { errorSimulator } -func newRedis(otelExporter string, logger log.Factory) *Redis { +func newRedis(otelExporter string, metricsFactory metrics.Factory, logger log.Factory) *Redis { return &Redis{ - tracer: tracing.Init("redis", otelExporter, logger), + tracer: tracing.Init("redis", otelExporter, metricsFactory, logger), logger: logger, } } diff --git a/examples/hotrod/services/driver/server.go b/examples/hotrod/services/driver/server.go index 7311bc66caa..da630555df8 100644 --- a/examples/hotrod/services/driver/server.go +++ b/examples/hotrod/services/driver/server.go @@ -26,6 +26,7 @@ import ( "github.com/jaegertracing/jaeger/examples/hotrod/pkg/log" "github.com/jaegertracing/jaeger/examples/hotrod/pkg/tracing" + "github.com/jaegertracing/jaeger/pkg/metrics" ) // Server implements jaeger-demo-frontend service @@ -40,8 +41,8 @@ type Server struct { var _ DriverServiceServer = (*Server)(nil) // NewServer creates a new driver.Server -func NewServer(hostPort string, otelExporter string, logger log.Factory) *Server { - tracer := tracing.Init("driver", otelExporter, logger) +func NewServer(hostPort string, otelExporter string, metricsFactory metrics.Factory, logger log.Factory) *Server { + tracer := tracing.Init("driver", otelExporter, metricsFactory, logger) server := grpc.NewServer(grpc.UnaryInterceptor( otgrpc.OpenTracingServerInterceptor(tracer)), grpc.StreamInterceptor( @@ -51,7 +52,7 @@ func NewServer(hostPort string, otelExporter string, logger log.Factory) *Server tracer: tracer, logger: logger, server: server, - redis: newRedis(otelExporter, logger), + redis: newRedis(otelExporter, metricsFactory, logger), } } diff --git a/internal/metricstest/metricstest.go b/internal/metricstest/metricstest.go index 954dd44ba45..530b3985f9e 100644 --- a/internal/metricstest/metricstest.go +++ b/internal/metricstest/metricstest.go @@ -48,7 +48,7 @@ func assertMetrics(t *testing.T, actualMetrics map[string]int64, expectedMetrics assert.EqualValues(t, expected.Value, actualMetrics[key], - "expected metric name: %s, tags: %+v", expected.Name, expected.Tags, + "expected metric name=%s tags: %+v; got: %+v", expected.Name, expected.Tags, actualMetrics, ) } } From 70887b138cf73b66b62740a64b245a2fff6a50c7 Mon Sep 17 00:00:00 2001 From: Yuri Shkuro Date: Sun, 29 Jan 2023 03:25:08 -0500 Subject: [PATCH 8/8] imports Signed-off-by: Yuri Shkuro --- examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go | 3 ++- examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go index 3268c9830fc..3db618115c4 100644 --- a/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go +++ b/examples/hotrod/pkg/tracing/rpcmetrics/metrics_test.go @@ -18,8 +18,9 @@ package rpcmetrics import ( "testing" - "github.com/jaegertracing/jaeger/internal/metricstest" "github.com/stretchr/testify/assert" + + "github.com/jaegertracing/jaeger/internal/metricstest" ) // E.g. tags("key", "value", "key", "value") diff --git a/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go b/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go index 4dfb65470bb..89f1db38695 100644 --- a/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go +++ b/examples/hotrod/pkg/tracing/rpcmetrics/observer_test.go @@ -26,7 +26,6 @@ import ( "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.7.0" - "github.com/opentracing/opentracing-go/ext" u "github.com/jaegertracing/jaeger/internal/metricstest"