Add a logger, standard tags, and round corners
Ben Sigelman
7 years ago
7 | 7 | "github.com/go-kit/kit/endpoint" |
8 | 8 | "github.com/go-kit/kit/examples/addsvc/pb" |
9 | 9 | "github.com/go-kit/kit/loadbalancer" |
10 | "github.com/go-kit/kit/log" | |
10 | 11 | kitot "github.com/go-kit/kit/tracing/opentracing" |
11 | 12 | grpctransport "github.com/go-kit/kit/transport/grpc" |
12 | 13 | "github.com/opentracing/opentracing-go" |
15 | 16 | // MakeSumEndpointFactory returns a loadbalancer.Factory that transforms GRPC |
16 | 17 | // host:port strings into Endpoints that call the Sum method on a GRPC server |
17 | 18 | // at that address. |
18 | func MakeSumEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
19 | func MakeSumEndpointFactory(tracer opentracing.Tracer, tracingLogger log.Logger) loadbalancer.Factory { | |
19 | 20 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { |
20 | 21 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) |
21 | 22 | return grpctransport.NewClient( |
25 | 26 | encodeSumRequest, |
26 | 27 | decodeSumResponse, |
27 | 28 | pb.SumReply{}, |
28 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer)), | |
29 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer, tracingLogger)), | |
29 | 30 | ).Endpoint(), cc, err |
30 | 31 | } |
31 | 32 | } |
33 | 34 | // MakeConcatEndpointFactory returns a loadbalancer.Factory that transforms |
34 | 35 | // GRPC host:port strings into Endpoints that call the Concat method on a GRPC |
35 | 36 | // server at that address. |
36 | func MakeConcatEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
37 | func MakeConcatEndpointFactory(tracer opentracing.Tracer, tracingLogger log.Logger) loadbalancer.Factory { | |
37 | 38 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { |
38 | 39 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) |
39 | 40 | return grpctransport.NewClient( |
43 | 44 | encodeConcatRequest, |
44 | 45 | decodeConcatResponse, |
45 | 46 | pb.ConcatReply{}, |
46 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer)), | |
47 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer, tracingLogger)), | |
47 | 48 | ).Endpoint(), cc, err |
48 | 49 | } |
49 | 50 | } |
6 | 6 | "github.com/go-kit/kit/endpoint" |
7 | 7 | "github.com/go-kit/kit/examples/addsvc/server" |
8 | 8 | "github.com/go-kit/kit/loadbalancer" |
9 | "github.com/go-kit/kit/log" | |
9 | 10 | kitot "github.com/go-kit/kit/tracing/opentracing" |
10 | 11 | httptransport "github.com/go-kit/kit/transport/http" |
11 | 12 | "github.com/opentracing/opentracing-go" |
15 | 16 | // an Endpoint. |
16 | 17 | // |
17 | 18 | // The path of the url is reset to /sum. |
18 | func MakeSumEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
19 | func MakeSumEndpointFactory(tracer opentracing.Tracer, tracingLogger log.Logger) loadbalancer.Factory { | |
19 | 20 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { |
20 | 21 | sumURL, err := url.Parse(instance) |
21 | 22 | if err != nil { |
29 | 30 | server.EncodeSumRequest, |
30 | 31 | server.DecodeSumResponse, |
31 | 32 | httptransport.SetClient(nil), |
32 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer)), | |
33 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer, tracingLogger)), | |
33 | 34 | ) |
34 | 35 | |
35 | 36 | return client.Endpoint(), nil, nil |
40 | 41 | // into an Endpoint. |
41 | 42 | // |
42 | 43 | // The path of the url is reset to /concat. |
43 | func MakeConcatEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
44 | func MakeConcatEndpointFactory(tracer opentracing.Tracer, tracingLogger log.Logger) loadbalancer.Factory { | |
44 | 45 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { |
45 | 46 | concatURL, err := url.Parse(instance) |
46 | 47 | if err != nil { |
54 | 55 | server.EncodeConcatRequest, |
55 | 56 | server.DecodeConcatResponse, |
56 | 57 | httptransport.SetClient(nil), |
57 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer)), | |
58 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer, tracingLogger)), | |
58 | 59 | ) |
59 | 60 | |
60 | 61 | return client.Endpoint(), nil, nil |
37 | 37 | thriftFramed = flag.Bool("thrift.framed", false, "true to enable framing") |
38 | 38 | |
39 | 39 | // Two OpenTracing backends (to demonstrate how they can be interchanged): |
40 | appdashHostport = flag.String("appdash_hostport", "", "Enable Appdash tracing via an Appdash server host:port") | |
41 | lightstepAccessToken = flag.String("lightstep_access_token", "", "Enable LightStep tracing via a LightStep access token") | |
40 | appdashAddr = flag.String("appdash.addr", "", "Enable Appdash tracing via an Appdash server host:port") | |
41 | lightstepAccessToken = flag.String("lightstep.token", "", "Enable LightStep tracing via a LightStep access token") | |
42 | 42 | ) |
43 | 43 | flag.Parse() |
44 | 44 | if len(os.Args) < 4 { |
56 | 56 | logger = log.NewLogfmtLogger(os.Stdout) |
57 | 57 | logger = log.NewContext(logger).With("caller", log.DefaultCaller) |
58 | 58 | logger = log.NewContext(logger).With("transport", *transport) |
59 | tracingLogger := log.NewContext(logger).With("component", "tracing") | |
59 | 60 | |
60 | 61 | // Set up OpenTracing |
61 | 62 | var tracer opentracing.Tracer |
62 | 63 | { |
63 | if len(*appdashHostport) > 0 { | |
64 | tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashHostport)) | |
65 | } | |
66 | if len(*lightstepAccessToken) > 0 { | |
67 | if tracer != nil { | |
68 | panic("Attempted to configure multiple OpenTracing implementations") | |
69 | } | |
64 | switch { | |
65 | case *appdashAddr != "" && *lightstepAccessToken == "": | |
66 | tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr)) | |
67 | case *appdashAddr == "" && *lightstepAccessToken != "": | |
70 | 68 | tracer = lightstep.NewTracer(lightstep.Options{ |
71 | 69 | AccessToken: *lightstepAccessToken, |
72 | 70 | }) |
73 | } | |
74 | if tracer == nil { | |
75 | tracer = opentracing.GlobalTracer() // the noop tracer | |
71 | defer lightstep.FlushLightStepTracer(tracer) | |
72 | case *appdashAddr == "" && *lightstepAccessToken == "": | |
73 | tracer = opentracing.GlobalTracer() // no-op | |
74 | default: | |
75 | panic("specify either -appdash.addr or -lightstep.access.token, not both") | |
76 | 76 | } |
77 | 77 | } |
78 | 78 | |
84 | 84 | switch *transport { |
85 | 85 | case "grpc": |
86 | 86 | instances = strings.Split(*grpcAddrs, ",") |
87 | sumFactory = grpcclient.MakeSumEndpointFactory(tracer) | |
88 | concatFactory = grpcclient.MakeConcatEndpointFactory(tracer) | |
87 | sumFactory = grpcclient.MakeSumEndpointFactory(tracer, tracingLogger) | |
88 | concatFactory = grpcclient.MakeConcatEndpointFactory(tracer, tracingLogger) | |
89 | 89 | |
90 | 90 | case "httpjson": |
91 | 91 | instances = strings.Split(*httpAddrs, ",") |
94 | 94 | instances[i] = "http://" + rawurl |
95 | 95 | } |
96 | 96 | } |
97 | sumFactory = httpjsonclient.MakeSumEndpointFactory(tracer) | |
98 | concatFactory = httpjsonclient.MakeConcatEndpointFactory(tracer) | |
97 | sumFactory = httpjsonclient.MakeSumEndpointFactory(tracer, tracingLogger) | |
98 | concatFactory = httpjsonclient.MakeConcatEndpointFactory(tracer, tracingLogger) | |
99 | 99 | |
100 | 100 | case "netrpc": |
101 | 101 | instances = strings.Split(*netrpcAddrs, ",") |
135 | 135 | logger.Log("err", "invalid method "+method) |
136 | 136 | os.Exit(1) |
137 | 137 | } |
138 | ||
139 | if len(*lightstepAccessToken) > 0 { | |
140 | lightstep.FlushLightStepTracer(tracer) | |
141 | } | |
142 | 138 | } |
143 | 139 | |
144 | 140 | func buildEndpoint(tracer opentracing.Tracer, operationName string, instances []string, factory loadbalancer.Factory, seed int64, logger log.Logger) endpoint.Endpoint { |
5 | 5 | "github.com/go-kit/kit/examples/addsvc/pb" |
6 | 6 | "github.com/go-kit/kit/examples/addsvc/server" |
7 | 7 | servergrpc "github.com/go-kit/kit/examples/addsvc/server/grpc" |
8 | "github.com/go-kit/kit/log" | |
8 | 9 | kitot "github.com/go-kit/kit/tracing/opentracing" |
9 | 10 | "github.com/go-kit/kit/transport/grpc" |
10 | 11 | "github.com/opentracing/opentracing-go" |
14 | 15 | sum, concat grpc.Handler |
15 | 16 | } |
16 | 17 | |
17 | func newGRPCBinding(ctx context.Context, tracer opentracing.Tracer, svc server.AddService) grpcBinding { | |
18 | func newGRPCBinding(ctx context.Context, tracer opentracing.Tracer, svc server.AddService, tracingLogger log.Logger) grpcBinding { | |
18 | 19 | return grpcBinding{ |
19 | 20 | sum: grpc.NewServer( |
20 | 21 | ctx, |
21 | 22 | kitot.TraceServer(tracer, "sum")(makeSumEndpoint(svc)), |
22 | 23 | servergrpc.DecodeSumRequest, |
23 | 24 | servergrpc.EncodeSumResponse, |
24 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "")), | |
25 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "", tracingLogger)), | |
25 | 26 | ), |
26 | 27 | concat: grpc.NewServer( |
27 | 28 | ctx, |
28 | 29 | kitot.TraceServer(tracer, "concat")(makeConcatEndpoint(svc)), |
29 | 30 | servergrpc.DecodeConcatRequest, |
30 | 31 | servergrpc.EncodeConcatResponse, |
31 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "")), | |
32 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "", tracingLogger)), | |
32 | 33 | ), |
33 | 34 | } |
34 | 35 | } |
50 | 50 | thriftFramed = fs.Bool("thrift.framed", false, "true to enable framing") |
51 | 51 | |
52 | 52 | // Supported OpenTracing backends |
53 | appdashHostport = fs.String("appdash_hostport", "", "Enable Appdash tracing via an Appdash server host:port") | |
54 | lightstepAccessToken = fs.String("lightstep_access_token", "", "Enable LightStep tracing via a LightStep access token") | |
53 | appdashAddr = fs.String("appdash.addr", "", "Enable Appdash tracing via an Appdash server host:port") | |
54 | lightstepAccessToken = fs.String("lightstep.token", "", "Enable LightStep tracing via a LightStep access token") | |
55 | 55 | ) |
56 | 56 | flag.Usage = fs.Usage // only show our flags |
57 | 57 | if err := fs.Parse(os.Args[1:]); err != nil { |
86 | 86 | // Set up OpenTracing |
87 | 87 | var tracer opentracing.Tracer |
88 | 88 | { |
89 | if len(*appdashHostport) > 0 { | |
90 | tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashHostport)) | |
91 | } | |
92 | if len(*lightstepAccessToken) > 0 { | |
93 | if tracer != nil { | |
94 | panic("Attempted to configure multiple OpenTracing implementations") | |
95 | } | |
89 | switch { | |
90 | case *appdashAddr != "" && *lightstepAccessToken == "": | |
91 | tracer = appdashot.NewTracer(appdash.NewRemoteCollector(*appdashAddr)) | |
92 | case *appdashAddr == "" && *lightstepAccessToken != "": | |
96 | 93 | tracer = lightstep.NewTracer(lightstep.Options{ |
97 | 94 | AccessToken: *lightstepAccessToken, |
98 | 95 | }) |
99 | } | |
100 | if tracer == nil { | |
101 | tracer = opentracing.GlobalTracer() // the noop tracer | |
96 | defer lightstep.FlushLightStepTracer(tracer) | |
97 | case *appdashAddr == "" && *lightstepAccessToken == "": | |
98 | tracer = opentracing.GlobalTracer() // no-op | |
99 | default: | |
100 | panic("specify either -appdash.addr or -lightstep.access.token, not both") | |
102 | 101 | } |
103 | 102 | } |
104 | 103 | |
130 | 129 | go func() { |
131 | 130 | var ( |
132 | 131 | transportLogger = log.NewContext(logger).With("transport", "HTTP/JSON") |
132 | tracingLogger = log.NewContext(transportLogger).With("component", "tracing") | |
133 | 133 | mux = http.NewServeMux() |
134 | 134 | sum, concat endpoint.Endpoint |
135 | 135 | ) |
142 | 142 | server.DecodeSumRequest, |
143 | 143 | server.EncodeSumResponse, |
144 | 144 | httptransport.ServerErrorLogger(transportLogger), |
145 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "sum")), | |
145 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "sum", tracingLogger)), | |
146 | 146 | )) |
147 | 147 | |
148 | 148 | concat = makeConcatEndpoint(svc) |
153 | 153 | server.DecodeConcatRequest, |
154 | 154 | server.EncodeConcatResponse, |
155 | 155 | httptransport.ServerErrorLogger(transportLogger), |
156 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "concat")), | |
156 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "concat", tracingLogger)), | |
157 | 157 | )) |
158 | 158 | |
159 | 159 | transportLogger.Log("addr", *httpAddr) |
163 | 163 | // Transport: gRPC |
164 | 164 | go func() { |
165 | 165 | transportLogger := log.NewContext(logger).With("transport", "gRPC") |
166 | tracingLogger := log.NewContext(transportLogger).With("component", "tracing") | |
166 | 167 | ln, err := net.Listen("tcp", *grpcAddr) |
167 | 168 | if err != nil { |
168 | 169 | errc <- err |
169 | 170 | return |
170 | 171 | } |
171 | 172 | s := grpc.NewServer() // uses its own, internal context |
172 | pb.RegisterAddServer(s, newGRPCBinding(root, tracer, svc)) | |
173 | pb.RegisterAddServer(s, newGRPCBinding(root, tracer, svc, tracingLogger)) | |
173 | 174 | transportLogger.Log("addr", *grpcAddr) |
174 | 175 | errc <- s.Serve(ln) |
175 | 176 | }() |
77 | 77 | factory loadbalancer.Factory |
78 | 78 | }{ |
79 | 79 | "addsvc": { |
80 | {path: "/api/addsvc/concat", factory: grpc.MakeConcatEndpointFactory(opentracing.GlobalTracer())}, | |
81 | {path: "/api/addsvc/sum", factory: grpc.MakeSumEndpointFactory(opentracing.GlobalTracer())}, | |
80 | {path: "/api/addsvc/concat", factory: grpc.MakeConcatEndpointFactory(opentracing.GlobalTracer(), nil)}, | |
81 | {path: "/api/addsvc/sum", factory: grpc.MakeSumEndpointFactory(opentracing.GlobalTracer(), nil)}, | |
82 | 82 | }, |
83 | 83 | "stringsvc": { |
84 | 84 | {path: "/api/stringsvc/uppercase", factory: httpFactory(ctx, "GET", "uppercase/")}, |
21 | 21 | } else { |
22 | 22 | serverSpan.SetOperationName(operationName) |
23 | 23 | } |
24 | defer serverSpan.Finish() | |
24 | 25 | otext.SpanKind.Set(serverSpan, otext.SpanKindRPCServer) |
25 | 26 | ctx = opentracing.ContextWithSpan(ctx, serverSpan) |
26 | defer serverSpan.Finish() | |
27 | 27 | return next(ctx, request) |
28 | 28 | } |
29 | 29 | } |
39 | 39 | OperationName: operationName, |
40 | 40 | Parent: parentSpan, // may be nil |
41 | 41 | }) |
42 | defer clientSpan.Finish() | |
42 | 43 | otext.SpanKind.Set(clientSpan, otext.SpanKindRPCClient) |
43 | 44 | ctx = opentracing.ContextWithSpan(ctx, clientSpan) |
44 | defer clientSpan.Finish() | |
45 | 45 | return next(ctx, request) |
46 | 46 | } |
47 | 47 | } |
0 | 0 | package opentracing |
1 | 1 | |
2 | 2 | import ( |
3 | "github.com/go-kit/kit/log" | |
3 | 4 | "github.com/opentracing/opentracing-go" |
4 | 5 | "golang.org/x/net/context" |
5 | 6 | "google.golang.org/grpc/metadata" |
8 | 9 | // ToGRPCRequest returns a grpc RequestFunc that injects an OpenTracing Span |
9 | 10 | // found in `ctx` into the grpc Metadata. If no such Span can be found, the |
10 | 11 | // RequestFunc is a noop. |
11 | func ToGRPCRequest(tracer opentracing.Tracer) func(ctx context.Context, md *metadata.MD) context.Context { | |
12 | // | |
13 | // The logger is used to report errors and may be nil. | |
14 | func ToGRPCRequest(tracer opentracing.Tracer, logger log.Logger) func(ctx context.Context, md *metadata.MD) context.Context { | |
12 | 15 | return func(ctx context.Context, md *metadata.MD) context.Context { |
13 | 16 | if span := opentracing.SpanFromContext(ctx); span != nil { |
14 | 17 | // There's nothing we can do with an error here. |
15 | _ = tracer.Inject(span, opentracing.TextMap, metadataReaderWriter{md}) | |
18 | err := tracer.Inject(span, opentracing.TextMap, metadataReaderWriter{md}) | |
19 | if err != nil && logger != nil { | |
20 | logger.Log("msg", "Inject failed", "err", err) | |
21 | } | |
16 | 22 | } |
17 | 23 | return ctx |
18 | 24 | } |
23 | 29 | // `operationName` accordingly. If no trace could be found in `req`, the Span |
24 | 30 | // will be a trace root. The Span is incorporated in the returned Context and |
25 | 31 | // can be retrieved with opentracing.SpanFromContext(ctx). |
26 | func FromGRPCRequest(tracer opentracing.Tracer, operationName string) func(ctx context.Context, md *metadata.MD) context.Context { | |
32 | // | |
33 | // The logger is used to report errors and may be nil. | |
34 | func FromGRPCRequest(tracer opentracing.Tracer, operationName string, logger log.Logger) func(ctx context.Context, md *metadata.MD) context.Context { | |
27 | 35 | return func(ctx context.Context, md *metadata.MD) context.Context { |
28 | 36 | span, err := tracer.Join(operationName, opentracing.TextMap, metadataReaderWriter{md}) |
29 | if err != nil || span == nil { | |
37 | if err != nil && logger != nil { | |
38 | logger.Log("msg", "Join failed", "err", err) | |
39 | } | |
40 | if span == nil { | |
30 | 41 | span = tracer.StartSpan(operationName) |
31 | 42 | } |
32 | 43 | return opentracing.ContextWithSpan(ctx, span) |
17 | 17 | // Initialize the ctx with a Span to inject. |
18 | 18 | beforeSpan := tracer.StartSpan("to_inject").(*mocktracer.MockSpan) |
19 | 19 | defer beforeSpan.Finish() |
20 | beforeSpan.SetBaggageItem("baggage", "check") | |
20 | 21 | beforeCtx := opentracing.ContextWithSpan(context.Background(), beforeSpan) |
21 | 22 | |
22 | var toGRPCFunc grpc.RequestFunc = kitot.ToGRPCRequest(tracer) | |
23 | var toGRPCFunc grpc.RequestFunc = kitot.ToGRPCRequest(tracer, nil) | |
23 | 24 | md := metadata.Pairs() |
24 | 25 | // Call the RequestFunc. |
25 | 26 | afterCtx := toGRPCFunc(beforeCtx, &md) |
36 | 37 | } |
37 | 38 | |
38 | 39 | // Use FromGRPCRequest to verify that we can join with the trace given MD. |
39 | var fromGRPCFunc grpc.RequestFunc = kitot.FromGRPCRequest(tracer, "joined") | |
40 | var fromGRPCFunc grpc.RequestFunc = kitot.FromGRPCRequest(tracer, "joined", nil) | |
40 | 41 | joinCtx := fromGRPCFunc(afterCtx, &md) |
41 | 42 | joinedSpan := opentracing.SpanFromContext(joinCtx).(*mocktracer.MockSpan) |
42 | 43 | |
51 | 52 | if want, have := "joined", joinedSpan.OperationName; want != have { |
52 | 53 | t.Errorf("Want %q, have %q", want, have) |
53 | 54 | } |
55 | if want, have := "check", joinedSpan.BaggageItem("baggage"); want != have { | |
56 | t.Errorf("Want %q, have %q", want, have) | |
57 | } | |
54 | 58 | } |
0 | 0 | package opentracing |
1 | 1 | |
2 | 2 | import ( |
3 | "net" | |
3 | 4 | "net/http" |
5 | "strconv" | |
4 | 6 | |
7 | "github.com/go-kit/kit/log" | |
5 | 8 | kithttp "github.com/go-kit/kit/transport/http" |
6 | 9 | "github.com/opentracing/opentracing-go" |
10 | "github.com/opentracing/opentracing-go/ext" | |
7 | 11 | "golang.org/x/net/context" |
8 | 12 | ) |
9 | 13 | |
10 | 14 | // ToHTTPRequest returns an http RequestFunc that injects an OpenTracing Span |
11 | 15 | // found in `ctx` into the http headers. If no such Span can be found, the |
12 | 16 | // RequestFunc is a noop. |
13 | func ToHTTPRequest(tracer opentracing.Tracer) kithttp.RequestFunc { | |
17 | // | |
18 | // The logger is used to report errors and may be nil. | |
19 | func ToHTTPRequest(tracer opentracing.Tracer, logger log.Logger) kithttp.RequestFunc { | |
14 | 20 | return func(ctx context.Context, req *http.Request) context.Context { |
15 | 21 | // Try to find a Span in the Context. |
16 | 22 | if span := opentracing.SpanFromContext(ctx); span != nil { |
23 | // Add standard OpenTracing tags. | |
24 | ext.HTTPMethod.Set(span, req.URL.RequestURI()) | |
25 | host, portString, err := net.SplitHostPort(req.URL.Host) | |
26 | if err == nil { | |
27 | ext.PeerHostname.Set(span, host) | |
28 | if port, err := strconv.Atoi(portString); err != nil { | |
29 | ext.PeerPort.Set(span, uint16(port)) | |
30 | } | |
31 | } else { | |
32 | ext.PeerHostname.Set(span, req.URL.Host) | |
33 | } | |
34 | ||
17 | 35 | // There's nothing we can do with any errors here. |
18 | _ = tracer.Inject(span, opentracing.TextMap, opentracing.HTTPHeaderTextMapCarrier(req.Header)) | |
36 | err = tracer.Inject( | |
37 | span, | |
38 | opentracing.TextMap, | |
39 | opentracing.HTTPHeaderTextMapCarrier(req.Header), | |
40 | ) | |
41 | if err != nil && logger != nil { | |
42 | logger.Log("msg", "Join failed", "err", err) | |
43 | } | |
19 | 44 | } |
20 | 45 | return ctx |
21 | 46 | } |
26 | 51 | // `operationName` accordingly. If no trace could be found in `req`, the Span |
27 | 52 | // will be a trace root. The Span is incorporated in the returned Context and |
28 | 53 | // can be retrieved with opentracing.SpanFromContext(ctx). |
29 | func FromHTTPRequest(tracer opentracing.Tracer, operationName string) kithttp.RequestFunc { | |
54 | // | |
55 | // The logger is used to report errors and may be nil. | |
56 | func FromHTTPRequest(tracer opentracing.Tracer, operationName string, logger log.Logger) kithttp.RequestFunc { | |
30 | 57 | return func(ctx context.Context, req *http.Request) context.Context { |
31 | 58 | // Try to join to a trace propagated in `req`. There's nothing we can |
32 | 59 | // do with any errors here, so we ignore them. |
33 | span, _ := tracer.Join(operationName, opentracing.TextMap, opentracing.HTTPHeaderTextMapCarrier(req.Header)) | |
60 | span, err := tracer.Join( | |
61 | operationName, | |
62 | opentracing.TextMap, | |
63 | opentracing.HTTPHeaderTextMapCarrier(req.Header), | |
64 | ) | |
65 | if err != nil && logger != nil { | |
66 | logger.Log("msg", "Join failed", "err", err) | |
67 | } | |
34 | 68 | if span == nil { |
35 | 69 | span = opentracing.StartSpan(operationName) |
36 | 70 | } |
16 | 16 | // Initialize the ctx with a Span to inject. |
17 | 17 | beforeSpan := tracer.StartSpan("to_inject").(*mocktracer.MockSpan) |
18 | 18 | defer beforeSpan.Finish() |
19 | beforeSpan.SetBaggageItem("baggage", "check") | |
19 | 20 | beforeCtx := opentracing.ContextWithSpan(context.Background(), beforeSpan) |
20 | 21 | |
21 | var toHTTPFunc kithttp.RequestFunc = kitot.ToHTTPRequest(tracer) | |
22 | var toHTTPFunc kithttp.RequestFunc = kitot.ToHTTPRequest(tracer, nil) | |
22 | 23 | req, _ := http.NewRequest("GET", "http://test.biz/url", nil) |
23 | 24 | // Call the RequestFunc. |
24 | 25 | afterCtx := toHTTPFunc(beforeCtx, req) |
35 | 36 | } |
36 | 37 | |
37 | 38 | // Use FromHTTPRequest to verify that we can join with the trace given a req. |
38 | var fromHTTPFunc kithttp.RequestFunc = kitot.FromHTTPRequest(tracer, "joined") | |
39 | var fromHTTPFunc kithttp.RequestFunc = kitot.FromHTTPRequest(tracer, "joined", nil) | |
39 | 40 | joinCtx := fromHTTPFunc(afterCtx, req) |
40 | 41 | joinedSpan := opentracing.SpanFromContext(joinCtx).(*mocktracer.MockSpan) |
41 | 42 | |
50 | 51 | if want, have := "joined", joinedSpan.OperationName; want != have { |
51 | 52 | t.Errorf("Want %q, have %q", want, have) |
52 | 53 | } |
54 | if want, have := "check", joinedSpan.BaggageItem("baggage"); want != have { | |
55 | t.Errorf("Want %q, have %q", want, have) | |
56 | } | |
53 | 57 | } |