Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hotROD] Upgrade hotrod to support otel tracer #4548

Merged
merged 23 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/hotrod/cmd/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var frontendCmd = &cobra.Command{
logger := log.NewFactory(zapLogger)
server := frontend.NewServer(
options,
tracing.Init("frontend", otelExporter, metricsFactory, logger),
tracing.InitOTEL("frontend", otelExporter, metricsFactory, logger),
afzal442 marked this conversation as resolved.
Show resolved Hide resolved
logger,
)
return logError(zapLogger, server.Run())
Expand Down
2 changes: 1 addition & 1 deletion examples/hotrod/cmd/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, metricsFactory, logger),
tracing.InitOTEL("route", otelExporter, metricsFactory, logger),
logger,
)
return logError(zapLogger, server.Run())
Expand Down
26 changes: 18 additions & 8 deletions examples/hotrod/pkg/tracing/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,37 @@
"io"
"net/http"

"github.com/opentracing-contrib/go-stdlib/nethttp"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
)

// HTTPClient wraps an http.Client with tracing instrumentation.
type HTTPClient struct {
Tracer opentracing.Tracer
Client *http.Client
TracerProvider trace.TracerProvider
Client *http.Client
}

func NewHTTPClient(tp trace.TracerProvider) *HTTPClient {
return &HTTPClient{
TracerProvider: tp,
Client: &http.Client{
Transport: otelhttp.NewTransport(
http.DefaultTransport,
otelhttp.WithTracerProvider(tp),
),
},
}
}

// GetJSON executes HTTP GET against specified url and tried to parse
// the response into out object.
func (c *HTTPClient) GetJSON(ctx context.Context, endpoint string, url string, out interface{}) error {
req, err := http.NewRequest(http.MethodGet, url, nil)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
req = req.WithContext(ctx)
req, ht := nethttp.TraceRequest(c.Tracer, req, nethttp.OperationName("HTTP GET: "+endpoint))
yurishkuro marked this conversation as resolved.
Show resolved Hide resolved
defer ht.Finish()

res, err := c.Client.Do(req)

Check failure

Code scanning / CodeQL

Uncontrolled data used in network request Critical

The
URL
of this request depends on a
user-provided value
.
if err != nil {
return err
}
Expand All @@ -57,6 +66,7 @@
}
return errors.New(string(body))
}

decoder := json.NewDecoder(res.Body)
return decoder.Decode(out)
}
4 changes: 2 additions & 2 deletions examples/hotrod/pkg/tracing/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ import (
var once sync.Once

// InitOTEL initializes OpenTelemetry SDK.
func InitOTEL(serviceName string, exporterType string, metricsFactory metrics.Factory, logger log.Factory) trace.Tracer {
func InitOTEL(serviceName string, exporterType string, metricsFactory metrics.Factory, logger log.Factory) trace.TracerProvider {
_, oteltp := initBOTH(serviceName, exporterType, metricsFactory, logger)

logger.Bg().Debug("Created OTEL tracer", zap.String("service-name", serviceName))
return oteltp.Tracer(serviceName)
return oteltp
afzal442 marked this conversation as resolved.
Show resolved Hide resolved
}

// Init returns OTel-OpenTracing Bridge.
Expand Down
50 changes: 10 additions & 40 deletions examples/hotrod/pkg/tracing/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@ package tracing
import (
"net/http"

"github.com/opentracing-contrib/go-stdlib/nethttp"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/log"
)

// NewServeMux creates a new TracedServeMux.
func NewServeMux(copyBaggage bool, tracer opentracing.Tracer, logger log.Factory) *TracedServeMux {
func NewServeMux(copyBaggage bool, tracer trace.TracerProvider, logger log.Factory) *TracedServeMux {
return &TracedServeMux{
mux: http.NewServeMux(),
copyBaggage: copyBaggage,
Expand All @@ -41,51 +39,23 @@ func NewServeMux(copyBaggage bool, tracer opentracing.Tracer, logger log.Factory
type TracedServeMux struct {
mux *http.ServeMux
copyBaggage bool
tracer opentracing.Tracer
tracer trace.TracerProvider
logger log.Factory
}

// Handle implements http.ServeMux#Handle, which is used to register new handler.
func (tm *TracedServeMux) Handle(pattern string, handler http.Handler) {
tm.logger.Bg().Debug("registering traced handler", zap.String("endpoint", pattern))

middleware := nethttp.Middleware(
tm.tracer,
handler,
nethttp.OperationNameFunc(func(r *http.Request) string {
return "HTTP " + r.Method + " " + pattern
}),
// Jaeger SDK was able to accept `jaeger-baggage` header even for requests without am active trace.
// OTEL Bridge does not support that, so we use Baggage propagator to manually extract the baggage
// into Context (in otelBaggageExtractor handler below), and once the Bridge creates a Span,
// we use this SpanObserver to copy OTEL baggage from Context into the Span.
nethttp.MWSpanObserver(func(span opentracing.Span, r *http.Request) {
if !tm.copyBaggage {
afzal442 marked this conversation as resolved.
Show resolved Hide resolved
return
}
bag := baggage.FromContext(r.Context())
for _, m := range bag.Members() {
if b := span.BaggageItem(m.Key()); b == "" {
span.SetBaggageItem(m.Key(), m.Value())
}
}
}),
)
tm.mux.Handle(pattern, otelBaggageExtractor(middleware))
middleware := otelhttp.NewHandler(
otelhttp.WithRouteTag(pattern, handler),
pattern,
otelhttp.WithTracerProvider(tm.tracer))

tm.mux.Handle(pattern, middleware)
afzal442 marked this conversation as resolved.
Show resolved Hide resolved
}

// ServeHTTP implements http.ServeMux#ServeHTTP.
func (tm *TracedServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
tm.mux.ServeHTTP(w, r)
}

// Used with nethttp.MWSpanObserver above.
func otelBaggageExtractor(next http.Handler) http.Handler {
propagator := propagation.Baggage{}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
carrier := propagation.HeaderCarrier(r.Header)
ctx := propagator.Extract(r.Context(), carrier)
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
15 changes: 4 additions & 11 deletions examples/hotrod/services/customer/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ package customer
import (
"context"
"fmt"
"net/http"

"github.com/opentracing-contrib/go-stdlib/nethttp"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/log"
Expand All @@ -30,21 +28,16 @@ import (

// Client is a remote client that implements customer.Interface
type Client struct {
tracer opentracing.Tracer
logger log.Factory
client *tracing.HTTPClient
hostPort string
}

// NewClient creates a new customer.Client
func NewClient(tracer opentracing.Tracer, logger log.Factory, hostPort string) *Client {
func NewClient(tracer trace.TracerProvider, logger log.Factory, hostPort string) *Client {
return &Client{
tracer: tracer,
logger: logger,
client: &tracing.HTTPClient{
Client: &http.Client{Transport: &nethttp.Transport{}},
Tracer: tracer,
},
logger: logger,
client: tracing.NewHTTPClient(tracer),
hostPort: hostPort,
}
}
Expand Down
6 changes: 3 additions & 3 deletions examples/hotrod/services/customer/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"encoding/json"
"net/http"

"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/httperr"
Expand All @@ -31,7 +31,7 @@ import (
// Server implements Customer service
type Server struct {
hostPort string
tracer opentracing.Tracer
tracer trace.TracerProvider
logger log.Factory
database *database
}
Expand All @@ -40,7 +40,7 @@ type Server struct {
func NewServer(hostPort string, otelExporter string, metricsFactory metrics.Factory, logger log.Factory) *Server {
return &Server{
hostPort: hostPort,
tracer: tracing.Init("customer", otelExporter, metricsFactory, logger),
tracer: tracing.InitOTEL("customer", otelExporter, metricsFactory, logger),
logger: logger,
database: newDatabase(
tracing.Init("mysql", otelExporter, metricsFactory, logger),
Expand Down
12 changes: 5 additions & 7 deletions examples/hotrod/services/driver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import (
"context"
"time"

otgrpc "github.com/opentracing-contrib/go-grpc"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
Expand All @@ -30,25 +30,23 @@ import (

// Client is a remote client that implements driver.Interface
type Client struct {
tracer opentracing.Tracer
logger log.Factory
client DriverServiceClient
}

// NewClient creates a new driver.Client
func NewClient(tracer opentracing.Tracer, logger log.Factory, hostPort string) *Client {
func NewClient(tracerProvider trace.TracerProvider, logger log.Factory, hostPort string) *Client {
conn, err := grpc.Dial(hostPort, grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUnaryInterceptor(
otgrpc.OpenTracingClientInterceptor(tracer)),
otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider))),
grpc.WithStreamInterceptor(
otgrpc.OpenTracingStreamClientInterceptor(tracer)))
otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider))))
afzal442 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
logger.Bg().Fatal("Cannot create gRPC connection", zap.Error(err))
}

client := NewDriverServiceClient(conn)
return &Client{
tracer: tracer,
logger: logger,
client: client,
}
Expand Down
3 changes: 2 additions & 1 deletion examples/hotrod/services/driver/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ type Redis struct {
}

func newRedis(otelExporter string, metricsFactory metrics.Factory, logger log.Factory) *Redis {
tp := tracing.InitOTEL("redis-manual", otelExporter, metricsFactory, logger)
return &Redis{
tracer: tracing.InitOTEL("redis-manual", otelExporter, metricsFactory, logger),
tracer: tp.Tracer("redis-manual"),
logger: logger,
}
}
Expand Down
13 changes: 8 additions & 5 deletions examples/hotrod/services/frontend/best_eta.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (
"sync"
"time"

"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/log"
Expand All @@ -47,7 +49,7 @@ type Response struct {
ETA time.Duration
}

func newBestETA(tracer opentracing.Tracer, logger log.Factory, options ConfigOptions) *bestETA {
func newBestETA(tracer trace.TracerProvider, logger log.Factory, options ConfigOptions) *bestETA {
return &bestETA{
customer: customer.NewClient(
tracer,
Expand Down Expand Up @@ -76,9 +78,10 @@ func (eta *bestETA) Get(ctx context.Context, customerID string) (*Response, erro
}
eta.logger.For(ctx).Info("Found customer", zap.Any("customer", customer))

if span := opentracing.SpanFromContext(ctx); span != nil {
span.SetBaggageItem("customer", customer.Name)
}
yurishkuro marked this conversation as resolved.
Show resolved Hide resolved
span := trace.SpanFromContext(ctx)
bag := baggage.FromContext(ctx)
m := bag.Member(customer.Name)
span.SetAttributes(attribute.Key(m.Key()).String(m.Value()))
afzal442 marked this conversation as resolved.
Show resolved Hide resolved

drivers, err := eta.driver.FindNearest(ctx, customer.Location)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions examples/hotrod/services/frontend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"net/http"
"path"

"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/httperr"
Expand All @@ -36,7 +36,7 @@ var assetFS embed.FS
// Server implements jaeger-demo-frontend service
type Server struct {
hostPort string
tracer opentracing.Tracer
tracer trace.TracerProvider
logger log.Factory
bestETA *bestETA
assetFS http.FileSystem
Expand All @@ -56,7 +56,7 @@ type ConfigOptions struct {
}

// NewServer creates a new frontend.Server
func NewServer(options ConfigOptions, tracer opentracing.Tracer, logger log.Factory) *Server {
func NewServer(options ConfigOptions, tracer trace.TracerProvider, logger log.Factory) *Server {
return &Server{
hostPort: options.FrontendHostPort,
tracer: tracer,
Expand Down
15 changes: 4 additions & 11 deletions examples/hotrod/services/route/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ package route

import (
"context"
"net/http"
"net/url"

"github.com/opentracing-contrib/go-stdlib/nethttp"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/log"
Expand All @@ -30,21 +28,16 @@ import (

// Client is a remote client that implements route.Interface
type Client struct {
tracer opentracing.Tracer
logger log.Factory
client *tracing.HTTPClient
hostPort string
}

// NewClient creates a new route.Client
func NewClient(tracer opentracing.Tracer, logger log.Factory, hostPort string) *Client {
func NewClient(tracer trace.TracerProvider, logger log.Factory, hostPort string) *Client {
return &Client{
tracer: tracer,
logger: logger,
client: &tracing.HTTPClient{
Client: &http.Client{Transport: &nethttp.Transport{}},
Tracer: tracer,
},
logger: logger,
client: tracing.NewHTTPClient(tracer),
hostPort: hostPort,
}
}
Expand Down