Skip to content

Commit

Permalink
refactors ot to otel trace
Browse files Browse the repository at this point in the history
  • Loading branch information
afzal442 committed Jun 26, 2023
1 parent b2a2648 commit 976d638
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 31 deletions.
73 changes: 69 additions & 4 deletions examples/hotrod/pkg/tracing/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,44 @@ import (
"errors"
"io"
"net/http"
"net/http/httptrace"
"net/url"

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

type contextKey int

const (
keyTracer contextKey = iota
)

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

// Tracer holds tracing details for one HTTP request.
type Tracer struct {
tp trace.TracerProvider
root trace.Span
sp trace.Span
opts *clientOptions
}

type clientOptions struct {
operationName string
componentName string
urlTagFunc func(u *url.URL) string
disableClientTrace bool
disableInjectSpanContext bool
spanObserver func(span trace.Span, r *http.Request)
}

// ClientOption contols the behavior of TraceRequest.
type ClientOption func(*clientOptions)

// 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 {
Expand All @@ -40,7 +67,7 @@ func (c *HTTPClient) GetJSON(ctx context.Context, endpoint string, url string, o
return err
}
req = req.WithContext(ctx)
req, ht := nethttp.TraceRequest(c.Tracer, req, nethttp.OperationName("HTTP GET: "+endpoint))
req, ht := c.TraceRequest(c.Tracer, req, c.OperationName("HTTP GET: "+endpoint))
defer ht.Finish()

res, err := c.Client.Do(req)
Expand All @@ -60,3 +87,41 @@ func (c *HTTPClient) GetJSON(ctx context.Context, endpoint string, url string, o
decoder := json.NewDecoder(res.Body)
return decoder.Decode(out)
}

func (c *HTTPClient) TraceRequest(tp trace.TracerProvider, req *http.Request, options ...ClientOption) (*http.Request, *Tracer) {
opts := &clientOptions{
urlTagFunc: func(u *url.URL) string {
return u.String()
},
spanObserver: func(_ trace.Span, _ *http.Request) {},
}
for _, opt := range options {
opt(opts)
}
ht := &Tracer{tp: tp, opts: opts}
ctx := req.Context()
if !opts.disableClientTrace {
ctx = httptrace.WithClientTrace(ctx, ht.clientTrace())
}
req = req.WithContext(context.WithValue(ctx, keyTracer, ht))
return req, ht
}

// OperationName returns a ClientOption that sets the operation
// name for the client-side span.
func (c *HTTPClient) OperationName(operationName string) ClientOption {
return func(options *clientOptions) {
options.operationName = operationName
}
}

// Finish finishes the span of the traced request.
func (h *Tracer) Finish() {
if h.root != nil {
h.root.End()
}
}

func (h *Tracer) clientTrace() *httptrace.ClientTrace {
return &httptrace.ClientTrace{}
}
18 changes: 12 additions & 6 deletions examples/hotrod/services/customer/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import (
"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,19 +29,26 @@ import (

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

// Transport wraps a RoundTripper. If a request is being traced with
// Tracer, Transport will inject the current span into the headers,
// and set HTTP related tags on the span.
type Transport struct {
// The actual RoundTripper to use for the request. A nil
// RoundTripper defaults to http.DefaultTransport.
http.RoundTripper
}

// 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{}},
Client: &http.Client{Transport: &Transport{}},
Tracer: tracer,
},
hostPort: hostPort,
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 {

Check warning on line 38 in examples/hotrod/services/driver/client.go

View check run for this annotation

Codecov / codecov/patch

examples/hotrod/services/driver/client.go#L38

Added line #L38 was not covered by tests
conn, err := grpc.Dial(hostPort, grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUnaryInterceptor(
otgrpc.OpenTracingClientInterceptor(tracer)),
otelgrpc.UnaryClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider))),

Check warning on line 41 in examples/hotrod/services/driver/client.go

View check run for this annotation

Codecov / codecov/patch

examples/hotrod/services/driver/client.go#L41

Added line #L41 was not covered by tests
grpc.WithStreamInterceptor(
otgrpc.OpenTracingStreamClientInterceptor(tracer)))
otelgrpc.StreamClientInterceptor(otelgrpc.WithTracerProvider(tracerProvider))))

Check warning on line 43 in examples/hotrod/services/driver/client.go

View check run for this annotation

Codecov / codecov/patch

examples/hotrod/services/driver/client.go#L43

Added line #L43 was not covered by tests
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
31 changes: 25 additions & 6 deletions examples/hotrod/services/driver/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ func TestFindNearest(t *testing.T) {
grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()),
).Serve(lis) */

// Call the FindNearest method
locationRequest := &DriverLocationRequest{
Location: "222,953",
}
Expand All @@ -55,17 +54,37 @@ func TestFindNearest(t *testing.T) {
// Assign the mock Redis to the server
server.redis = mockRedis

// Call the FindNearest method
response, err := server.FindNearest(ctx, locationRequest)

// server.redis.FindDriverIDs(ctx, locationRequest.Location)
driverIDs := server.redis.FindDriverIDs(ctx, locationRequest.Location)

// server.redis.GetDriver(ctx, driverId)
retMe := make([]*DriverLocation, len(driverIDs))
for i, driverID := range driverIDs {
var drv Driver
var err error
for i := 0; i < 3; i++ {
drv, err = server.redis.GetDriver(ctx, driverID)
if err == nil {
break
}
server.logger.For(ctx).Error("Retrying GetDriver after error", zap.Int("retry_no", i+1), zap.Error(err))
}
if err != nil {
server.logger.For(ctx).Error("Failed to get driver after 3 attempts", zap.Error(err))
return
}
retMe[i] = &DriverLocation{
DriverID: drv.DriverID,
Location: drv.Location,
}
}

// Assert the expected results
assert.NoError(t, err)
assert.NotNil(t, response)
assert.Equal(t, 10, len(response.Locations))
// assert.Equal(t, "T723310C", response.Locations[0].DriverID)
// assert.Equal(t, "222,953", response.Locations[0].Location)
assert.Equal(t, len(retMe), len(response.Locations))
// assert.Equal(t, retMe[0].DriverID, response.Locations[0].DriverID)
// assert.Equal(t, retMe[0].Location, response.Locations[0].Location)
// Add more assertions as needed
}
3 changes: 2 additions & 1 deletion examples/hotrod/services/frontend/best_eta.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"time"

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

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/log"
Expand All @@ -47,7 +48,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
4 changes: 3 additions & 1 deletion examples/hotrod/services/frontend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"path"

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

"github.com/jaegertracing/jaeger/examples/hotrod/pkg/httperr"
Expand Down Expand Up @@ -57,11 +58,12 @@ type ConfigOptions struct {

// NewServer creates a new frontend.Server
func NewServer(options ConfigOptions, tracer opentracing.Tracer, logger log.Factory) *Server {
var traceProvider trace.TracerProvider
return &Server{
hostPort: options.FrontendHostPort,
tracer: tracer,
logger: logger,
bestETA: newBestETA(tracer, logger, options),
bestETA: newBestETA(traceProvider, logger, options),
assetFS: httpfs.PrefixedFS("web_assets", http.FS(assetFS)),
basepath: options.Basepath,
jaegerUI: options.JaegerUI,
Expand Down
18 changes: 12 additions & 6 deletions examples/hotrod/services/route/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import (
"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,19 +29,26 @@ import (

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

// Transport wraps a RoundTripper. If a request is being traced with
// Tracer, Transport will inject the current span into the headers,
// and set HTTP related tags on the span.
type Transport struct {
// The actual RoundTripper to use for the request. A nil
// RoundTripper defaults to http.DefaultTransport.
http.RoundTripper
}

// 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{}},
Client: &http.Client{Transport: Transport{}},
Tracer: tracer,
},
hostPort: hostPort,
Expand Down

0 comments on commit 976d638

Please sign in to comment.