...
1 package opentracing
2
3 import (
4 "context"
5 "strconv"
6
7 "github.com/opentracing/opentracing-go"
8 otext "github.com/opentracing/opentracing-go/ext"
9 otlog "github.com/opentracing/opentracing-go/log"
10
11 "github.com/go-kit/kit/endpoint"
12 "github.com/go-kit/kit/sd/lb"
13 )
14
15
16
17
18
19
20 func TraceEndpoint(tracer opentracing.Tracer, operationName string, opts ...EndpointOption) endpoint.Middleware {
21 cfg := &EndpointOptions{
22 Tags: make(opentracing.Tags),
23 }
24
25 for _, opt := range opts {
26 opt(cfg)
27 }
28
29 return func(next endpoint.Endpoint) endpoint.Endpoint {
30 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
31 if cfg.GetOperationName != nil {
32 if newOperationName := cfg.GetOperationName(ctx, operationName); newOperationName != "" {
33 operationName = newOperationName
34 }
35 }
36
37 var span opentracing.Span
38 if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil {
39 span = tracer.StartSpan(
40 operationName,
41 opentracing.ChildOf(parentSpan.Context()),
42 )
43 } else {
44 span = tracer.StartSpan(operationName)
45 }
46 defer span.Finish()
47
48 applyTags(span, cfg.Tags)
49 if cfg.GetTags != nil {
50 extraTags := cfg.GetTags(ctx)
51 applyTags(span, extraTags)
52 }
53
54 ctx = opentracing.ContextWithSpan(ctx, span)
55
56 defer func() {
57 if err != nil {
58 if lbErr, ok := err.(lb.RetryError); ok {
59
60 fields := make([]otlog.Field, 0, len(lbErr.RawErrors))
61 for idx, rawErr := range lbErr.RawErrors {
62 fields = append(fields, otlog.String(
63 "gokit.retry.error."+strconv.Itoa(idx+1), rawErr.Error(),
64 ))
65 }
66
67 otext.LogError(span, lbErr, fields...)
68
69 return
70 }
71
72
73 otext.LogError(span, err)
74
75 return
76 }
77
78
79 if res, ok := response.(endpoint.Failer); ok && res.Failed() != nil {
80 span.LogFields(
81 otlog.String("gokit.business.error", res.Failed().Error()),
82 )
83
84 if cfg.IgnoreBusinessError {
85 return
86 }
87
88
89 otext.LogError(span, res.Failed())
90
91 return
92 }
93 }()
94
95 return next(ctx, request)
96 }
97 }
98 }
99
100
101
102 func TraceServer(tracer opentracing.Tracer, operationName string, opts ...EndpointOption) endpoint.Middleware {
103 opts = append(opts, WithTags(map[string]interface{}{
104 otext.SpanKindRPCServer.Key: otext.SpanKindRPCServer.Value,
105 }))
106
107 return TraceEndpoint(tracer, operationName, opts...)
108 }
109
110
111
112 func TraceClient(tracer opentracing.Tracer, operationName string, opts ...EndpointOption) endpoint.Middleware {
113 opts = append(opts, WithTags(map[string]interface{}{
114 otext.SpanKindRPCClient.Key: otext.SpanKindRPCClient.Value,
115 }))
116
117 return TraceEndpoint(tracer, operationName, opts...)
118 }
119
120 func applyTags(span opentracing.Span, tags opentracing.Tags) {
121 for key, value := range tags {
122 span.SetTag(key, value)
123 }
124 }
125
View as plain text