Demonstrate the OpenTracing bindings via addsvc
Rather than support both Zipkin and OpenTracing, this diff replaces the
former with the latter. It would be feasible to support both, though.
Ben Sigelman
8 years ago
6 | 6 | |
7 | 7 | "github.com/go-kit/kit/endpoint" |
8 | 8 | "github.com/go-kit/kit/examples/addsvc/pb" |
9 | "github.com/go-kit/kit/loadbalancer" | |
10 | kitot "github.com/go-kit/kit/tracing/opentracing" | |
9 | 11 | grpctransport "github.com/go-kit/kit/transport/grpc" |
12 | "github.com/opentracing/opentracing-go" | |
10 | 13 | ) |
11 | 14 | |
12 | 15 | // SumEndpointFactory transforms GRPC host:port strings into Endpoints that call the Sum method on a GRPC server |
13 | 16 | // at that address. |
14 | func SumEndpointFactory(instance string) (endpoint.Endpoint, io.Closer, error) { | |
15 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) | |
16 | return grpctransport.NewClient( | |
17 | cc, | |
18 | "Add", | |
19 | "Sum", | |
20 | encodeSumRequest, | |
21 | decodeSumResponse, | |
22 | pb.SumReply{}, | |
23 | ).Endpoint(), cc, err | |
17 | func NewSumEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
18 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { | |
19 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) | |
20 | return grpctransport.NewClient( | |
21 | cc, | |
22 | "Add", | |
23 | "Sum", | |
24 | encodeSumRequest, | |
25 | decodeSumResponse, | |
26 | pb.SumReply{}, | |
27 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer)), | |
28 | ).Endpoint(), cc, err | |
29 | } | |
24 | 30 | } |
25 | 31 | |
26 | 32 | // ConcatEndpointFactory transforms GRPC host:port strings into Endpoints that call the Concat method on a GRPC server |
27 | 33 | // at that address. |
28 | func ConcatEndpointFactory(instance string) (endpoint.Endpoint, io.Closer, error) { | |
29 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) | |
30 | return grpctransport.NewClient( | |
31 | cc, | |
32 | "Add", | |
33 | "Concat", | |
34 | encodeConcatRequest, | |
35 | decodeConcatResponse, | |
36 | pb.ConcatReply{}, | |
37 | ).Endpoint(), cc, err | |
34 | func NewConcatEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
35 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { | |
36 | cc, err := grpc.Dial(instance, grpc.WithInsecure()) | |
37 | return grpctransport.NewClient( | |
38 | cc, | |
39 | "Add", | |
40 | "Concat", | |
41 | encodeConcatRequest, | |
42 | decodeConcatResponse, | |
43 | pb.ConcatReply{}, | |
44 | grpctransport.SetClientBefore(kitot.ToGRPCRequest(tracer)), | |
45 | ).Endpoint(), cc, err | |
46 | } | |
38 | 47 | } |
5 | 5 | |
6 | 6 | "github.com/go-kit/kit/endpoint" |
7 | 7 | "github.com/go-kit/kit/examples/addsvc/server" |
8 | "github.com/go-kit/kit/loadbalancer" | |
9 | kitot "github.com/go-kit/kit/tracing/opentracing" | |
8 | 10 | httptransport "github.com/go-kit/kit/transport/http" |
11 | "github.com/opentracing/opentracing-go" | |
9 | 12 | ) |
10 | 13 | |
11 | // SumEndpointFactory transforms a http url into an Endpoint. | |
14 | // SumEndpointFactory generates a Factory that transforms an http url into an | |
15 | // Endpoint. | |
16 | // | |
12 | 17 | // The path of the url is reset to /sum. |
13 | func SumEndpointFactory(instance string) (endpoint.Endpoint, io.Closer, error) { | |
14 | sumURL, err := url.Parse(instance) | |
15 | if err != nil { | |
16 | return nil, nil, err | |
18 | func NewSumEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
19 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { | |
20 | sumURL, err := url.Parse(instance) | |
21 | if err != nil { | |
22 | return nil, nil, err | |
23 | } | |
24 | sumURL.Path = "/sum" | |
25 | ||
26 | client := httptransport.NewClient( | |
27 | "GET", | |
28 | sumURL, | |
29 | server.EncodeSumRequest, | |
30 | server.DecodeSumResponse, | |
31 | httptransport.SetClient(nil), | |
32 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer)), | |
33 | ) | |
34 | ||
35 | return client.Endpoint(), nil, nil | |
17 | 36 | } |
18 | sumURL.Path = "/sum" | |
19 | ||
20 | client := httptransport.NewClient( | |
21 | "GET", | |
22 | sumURL, | |
23 | server.EncodeSumRequest, | |
24 | server.DecodeSumResponse, | |
25 | httptransport.SetClient(nil), | |
26 | ) | |
27 | ||
28 | return client.Endpoint(), nil, nil | |
29 | 37 | } |
30 | 38 | |
31 | // ConcatEndpointFactory transforms a http url into an Endpoint. | |
39 | // NewConcatEndpointFactory generates a Factory that transforms an http url | |
40 | // into an Endpoint. | |
41 | // | |
32 | 42 | // The path of the url is reset to /concat. |
33 | func ConcatEndpointFactory(instance string) (endpoint.Endpoint, io.Closer, error) { | |
34 | concatURL, err := url.Parse(instance) | |
35 | if err != nil { | |
36 | return nil, nil, err | |
43 | func NewConcatEndpointFactory(tracer opentracing.Tracer) loadbalancer.Factory { | |
44 | return func(instance string) (endpoint.Endpoint, io.Closer, error) { | |
45 | concatURL, err := url.Parse(instance) | |
46 | if err != nil { | |
47 | return nil, nil, err | |
48 | } | |
49 | concatURL.Path = "/concat" | |
50 | ||
51 | client := httptransport.NewClient( | |
52 | "GET", | |
53 | concatURL, | |
54 | server.EncodeConcatRequest, | |
55 | server.DecodeConcatResponse, | |
56 | httptransport.SetClient(nil), | |
57 | httptransport.SetClientBefore(kitot.ToHTTPRequest(tracer)), | |
58 | ) | |
59 | ||
60 | return client.Endpoint(), nil, nil | |
37 | 61 | } |
38 | concatURL.Path = "/concat" | |
39 | ||
40 | client := httptransport.NewClient( | |
41 | "GET", | |
42 | concatURL, | |
43 | server.EncodeConcatRequest, | |
44 | server.DecodeConcatResponse, | |
45 | httptransport.SetClient(nil), | |
46 | ) | |
47 | ||
48 | return client.Endpoint(), nil, nil | |
49 | 62 | } |
18 | 18 | "github.com/go-kit/kit/loadbalancer" |
19 | 19 | "github.com/go-kit/kit/loadbalancer/static" |
20 | 20 | "github.com/go-kit/kit/log" |
21 | kitot "github.com/go-kit/kit/tracing/opentracing" | |
22 | "github.com/lightstep/lightstep-tracer-go" | |
23 | "github.com/opentracing/opentracing-go" | |
24 | appdashot "github.com/sourcegraph/appdash/opentracing" | |
25 | "sourcegraph.com/sourcegraph/appdash" | |
21 | 26 | ) |
22 | 27 | |
23 | 28 | func main() { |
30 | 35 | thriftProtocol = flag.String("thrift.protocol", "binary", "binary, compact, json, simplejson") |
31 | 36 | thriftBufferSize = flag.Int("thrift.buffer.size", 0, "0 for unbuffered") |
32 | 37 | thriftFramed = flag.Bool("thrift.framed", false, "true to enable framing") |
38 | ||
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") | |
33 | 42 | ) |
34 | 43 | flag.Parse() |
35 | 44 | if len(os.Args) < 4 { |
48 | 57 | logger = log.NewContext(logger).With("caller", log.DefaultCaller) |
49 | 58 | logger = log.NewContext(logger).With("transport", *transport) |
50 | 59 | |
60 | // Set up OpenTracing | |
61 | var tracer opentracing.Tracer | |
62 | { | |
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 | } | |
70 | tracer = lightstep.NewTracer(lightstep.Options{ | |
71 | AccessToken: *lightstepAccessToken, | |
72 | }) | |
73 | } | |
74 | if tracer == nil { | |
75 | tracer = opentracing.GlobalTracer() // the noop tracer | |
76 | } | |
77 | } | |
78 | ||
51 | 79 | var ( |
52 | 80 | instances []string |
53 | 81 | sumFactory, concatFactory loadbalancer.Factory |
56 | 84 | switch *transport { |
57 | 85 | case "grpc": |
58 | 86 | instances = strings.Split(*grpcAddrs, ",") |
59 | sumFactory = grpcclient.SumEndpointFactory | |
60 | concatFactory = grpcclient.ConcatEndpointFactory | |
87 | sumFactory = grpcclient.NewSumEndpointFactory(tracer) | |
88 | concatFactory = grpcclient.NewConcatEndpointFactory(tracer) | |
61 | 89 | |
62 | 90 | case "httpjson": |
63 | 91 | instances = strings.Split(*httpAddrs, ",") |
66 | 94 | instances[i] = "http://" + rawurl |
67 | 95 | } |
68 | 96 | } |
69 | sumFactory = httpjsonclient.SumEndpointFactory | |
70 | concatFactory = httpjsonclient.ConcatEndpointFactory | |
97 | sumFactory = httpjsonclient.NewSumEndpointFactory(tracer) | |
98 | concatFactory = httpjsonclient.NewConcatEndpointFactory(tracer) | |
71 | 99 | |
72 | 100 | case "netrpc": |
73 | 101 | instances = strings.Split(*netrpcAddrs, ",") |
85 | 113 | os.Exit(1) |
86 | 114 | } |
87 | 115 | |
88 | sum := buildEndpoint(instances, sumFactory, randomSeed, logger) | |
89 | concat := buildEndpoint(instances, concatFactory, randomSeed, logger) | |
116 | sum := buildEndpoint(tracer, "sum", instances, sumFactory, randomSeed, logger) | |
117 | concat := buildEndpoint(tracer, "concat", instances, concatFactory, randomSeed, logger) | |
90 | 118 | |
91 | 119 | svc := newClient(root, sum, concat, logger) |
92 | 120 | |
107 | 135 | logger.Log("err", "invalid method "+method) |
108 | 136 | os.Exit(1) |
109 | 137 | } |
138 | ||
139 | if len(*lightstepAccessToken) > 0 { | |
140 | lightstep.FlushLightStepTracer(tracer) | |
141 | } | |
110 | 142 | } |
111 | 143 | |
112 | func buildEndpoint(instances []string, factory loadbalancer.Factory, seed int64, logger log.Logger) endpoint.Endpoint { | |
144 | func buildEndpoint(tracer opentracing.Tracer, operationName string, instances []string, factory loadbalancer.Factory, seed int64, logger log.Logger) endpoint.Endpoint { | |
113 | 145 | publisher := static.NewPublisher(instances, factory, logger) |
114 | 146 | random := loadbalancer.NewRandom(publisher, seed) |
115 | return loadbalancer.Retry(10, 10*time.Second, random) | |
147 | endpoint := loadbalancer.Retry(10, 10*time.Second, random) | |
148 | return kitot.TraceClient(tracer, operationName)(endpoint) | |
116 | 149 | } |
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 | kitot "github.com/go-kit/kit/tracing/opentracing" | |
8 | 9 | "github.com/go-kit/kit/transport/grpc" |
10 | "github.com/opentracing/opentracing-go" | |
9 | 11 | ) |
10 | 12 | |
11 | 13 | type grpcBinding struct { |
12 | 14 | sum, concat grpc.Handler |
13 | 15 | } |
14 | 16 | |
15 | func newGRPCBinding(ctx context.Context, svc server.AddService) grpcBinding { | |
17 | func newGRPCBinding(ctx context.Context, tracer opentracing.Tracer, svc server.AddService) grpcBinding { | |
16 | 18 | return grpcBinding{ |
17 | sum: grpc.NewServer(ctx, makeSumEndpoint(svc), servergrpc.DecodeSumRequest, servergrpc.EncodeSumResponse), | |
18 | concat: grpc.NewServer(ctx, makeConcatEndpoint(svc), servergrpc.DecodeConcatRequest, servergrpc.EncodeConcatResponse), | |
19 | sum: grpc.NewServer( | |
20 | ctx, | |
21 | kitot.TraceServer(tracer, "sum")(makeSumEndpoint(svc)), | |
22 | servergrpc.DecodeSumRequest, | |
23 | servergrpc.EncodeSumResponse, | |
24 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "")), | |
25 | ), | |
26 | concat: grpc.NewServer( | |
27 | ctx, | |
28 | kitot.TraceServer(tracer, "concat")(makeConcatEndpoint(svc)), | |
29 | servergrpc.DecodeConcatRequest, | |
30 | servergrpc.EncodeConcatResponse, | |
31 | grpc.ServerBefore(kitot.FromGRPCRequest(tracer, "")), | |
32 | ), | |
19 | 33 | } |
20 | 34 | } |
21 | 35 |
14 | 14 | "time" |
15 | 15 | |
16 | 16 | "github.com/apache/thrift/lib/go/thrift" |
17 | kitot "github.com/go-kit/kit/tracing/opentracing" | |
18 | "github.com/lightstep/lightstep-tracer-go" | |
19 | "github.com/opentracing/opentracing-go" | |
17 | 20 | stdprometheus "github.com/prometheus/client_golang/prometheus" |
21 | appdashot "github.com/sourcegraph/appdash/opentracing" | |
18 | 22 | "golang.org/x/net/context" |
19 | 23 | "google.golang.org/grpc" |
24 | "sourcegraph.com/sourcegraph/appdash" | |
20 | 25 | |
21 | 26 | "github.com/go-kit/kit/endpoint" |
22 | 27 | "github.com/go-kit/kit/examples/addsvc/pb" |
35 | 40 | // of glog. So, we define a new flag set, to keep those domains distinct. |
36 | 41 | fs := flag.NewFlagSet("", flag.ExitOnError) |
37 | 42 | var ( |
38 | debugAddr = fs.String("debug.addr", ":8000", "Address for HTTP debug/instrumentation server") | |
39 | httpAddr = fs.String("http.addr", ":8001", "Address for HTTP (JSON) server") | |
40 | grpcAddr = fs.String("grpc.addr", ":8002", "Address for gRPC server") | |
41 | netrpcAddr = fs.String("netrpc.addr", ":8003", "Address for net/rpc server") | |
42 | thriftAddr = fs.String("thrift.addr", ":8004", "Address for Thrift server") | |
43 | thriftProtocol = fs.String("thrift.protocol", "binary", "binary, compact, json, simplejson") | |
44 | thriftBufferSize = fs.Int("thrift.buffer.size", 0, "0 for unbuffered") | |
45 | thriftFramed = fs.Bool("thrift.framed", false, "true to enable framing") | |
46 | zipkinHostPort = fs.String("zipkin.host.port", "my.service.domain:12345", "Zipkin host:port") | |
47 | zipkinServiceName = fs.String("zipkin.service.name", "addsvc", "Zipkin service name") | |
48 | zipkinCollectorAddr = fs.String("zipkin.collector.addr", "", "Zipkin Kafka collector address (empty will log spans)") | |
43 | debugAddr = fs.String("debug.addr", ":8000", "Address for HTTP debug/instrumentation server") | |
44 | httpAddr = fs.String("http.addr", ":8001", "Address for HTTP (JSON) server") | |
45 | grpcAddr = fs.String("grpc.addr", ":8002", "Address for gRPC server") | |
46 | netrpcAddr = fs.String("netrpc.addr", ":8003", "Address for net/rpc server") | |
47 | thriftAddr = fs.String("thrift.addr", ":8004", "Address for Thrift server") | |
48 | thriftProtocol = fs.String("thrift.protocol", "binary", "binary, compact, json, simplejson") | |
49 | thriftBufferSize = fs.Int("thrift.buffer.size", 0, "0 for unbuffered") | |
50 | thriftFramed = fs.Bool("thrift.framed", false, "true to enable framing") | |
51 | ||
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") | |
49 | 55 | ) |
50 | 56 | flag.Usage = fs.Usage // only show our flags |
51 | 57 | if err := fs.Parse(os.Args[1:]); err != nil { |
77 | 83 | )) |
78 | 84 | } |
79 | 85 | |
80 | // package tracing | |
81 | var collector zipkin.Collector | |
82 | { | |
83 | zipkinLogger := log.NewContext(logger).With("component", "zipkin") | |
84 | collector = loggingCollector{zipkinLogger} // TODO(pb) | |
85 | if *zipkinCollectorAddr != "" { | |
86 | var err error | |
87 | if collector, err = zipkin.NewKafkaCollector( | |
88 | []string{*zipkinCollectorAddr}, | |
89 | zipkin.KafkaLogger(zipkinLogger), | |
90 | ); err != nil { | |
91 | zipkinLogger.Log("err", err) | |
92 | os.Exit(1) | |
86 | // Set up OpenTracing | |
87 | var tracer opentracing.Tracer | |
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") | |
93 | 95 | } |
96 | tracer = lightstep.NewTracer(lightstep.Options{ | |
97 | AccessToken: *lightstepAccessToken, | |
98 | }) | |
99 | } | |
100 | if tracer == nil { | |
101 | tracer = opentracing.GlobalTracer() // the noop tracer | |
94 | 102 | } |
95 | 103 | } |
96 | 104 | |
122 | 130 | go func() { |
123 | 131 | var ( |
124 | 132 | transportLogger = log.NewContext(logger).With("transport", "HTTP/JSON") |
125 | tracingLogger = log.NewContext(transportLogger).With("component", "tracing") | |
126 | newSumSpan = zipkin.MakeNewSpanFunc(*zipkinHostPort, *zipkinServiceName, "sum") | |
127 | newConcatSpan = zipkin.MakeNewSpanFunc(*zipkinHostPort, *zipkinServiceName, "concat") | |
128 | traceSum = zipkin.ToContext(newSumSpan, tracingLogger) | |
129 | traceConcat = zipkin.ToContext(newConcatSpan, tracingLogger) | |
130 | 133 | mux = http.NewServeMux() |
131 | 134 | sum, concat endpoint.Endpoint |
132 | 135 | ) |
133 | 136 | |
134 | 137 | sum = makeSumEndpoint(svc) |
135 | sum = zipkin.AnnotateServer(newSumSpan, collector)(sum) | |
138 | sum = kitot.TraceServer(tracer, "sum")(sum) | |
136 | 139 | mux.Handle("/sum", httptransport.NewServer( |
137 | 140 | root, |
138 | 141 | sum, |
139 | 142 | server.DecodeSumRequest, |
140 | 143 | server.EncodeSumResponse, |
141 | httptransport.ServerBefore(traceSum), | |
142 | 144 | httptransport.ServerErrorLogger(transportLogger), |
145 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "sum")), | |
143 | 146 | )) |
144 | 147 | |
145 | 148 | concat = makeConcatEndpoint(svc) |
146 | concat = zipkin.AnnotateServer(newConcatSpan, collector)(concat) | |
149 | concat = kitot.TraceServer(tracer, "concat")(concat) | |
147 | 150 | mux.Handle("/concat", httptransport.NewServer( |
148 | 151 | root, |
149 | 152 | concat, |
150 | 153 | server.DecodeConcatRequest, |
151 | 154 | server.EncodeConcatResponse, |
152 | httptransport.ServerBefore(traceConcat), | |
153 | 155 | httptransport.ServerErrorLogger(transportLogger), |
156 | httptransport.ServerBefore(kitot.FromHTTPRequest(tracer, "concat")), | |
154 | 157 | )) |
155 | 158 | |
156 | 159 | transportLogger.Log("addr", *httpAddr) |
166 | 169 | return |
167 | 170 | } |
168 | 171 | s := grpc.NewServer() // uses its own, internal context |
169 | pb.RegisterAddServer(s, newGRPCBinding(root, svc)) | |
172 | pb.RegisterAddServer(s, newGRPCBinding(root, tracer, svc)) | |
170 | 173 | transportLogger.Log("addr", *grpcAddr) |
171 | 174 | errc <- s.Serve(ln) |
172 | 175 | }() |
9 | 9 | |
10 | 10 | type pureAddService struct{} |
11 | 11 | |
12 | func (pureAddService) Sum(a, b int) int { return a + b } | |
12 | func (pureAddService) Sum(a, b int) int { | |
13 | return a + b | |
14 | } | |
13 | 15 | |
14 | 16 | func (pureAddService) Concat(a, b string) string { return a + b } |
15 | 17 |
16 | 16 | |
17 | 17 | "github.com/gorilla/mux" |
18 | 18 | "github.com/hashicorp/consul/api" |
19 | "github.com/opentracing/opentracing-go" | |
19 | 20 | "golang.org/x/net/context" |
20 | 21 | |
21 | 22 | "github.com/go-kit/kit/endpoint" |
76 | 77 | factory loadbalancer.Factory |
77 | 78 | }{ |
78 | 79 | "addsvc": { |
79 | {path: "/api/addsvc/concat", factory: grpc.ConcatEndpointFactory}, | |
80 | {path: "/api/addsvc/sum", factory: grpc.SumEndpointFactory}, | |
80 | {path: "/api/addsvc/concat", factory: grpc.NewConcatEndpointFactory(opentracing.GlobalTracer())}, | |
81 | {path: "/api/addsvc/sum", factory: grpc.NewSumEndpointFactory(opentracing.GlobalTracer())}, | |
81 | 82 | }, |
82 | 83 | "stringsvc": { |
83 | 84 | {path: "/api/stringsvc/uppercase", factory: httpFactory(ctx, "GET", "uppercase/")}, |