Codebase list golang-github-go-kit-kit / e5c83b1
refactor(tracing.opentracing): standardize - support lb.Retry errors - add more logging fields as it done in opencensus - log business error anyway - improve codebase - fix typo - add more test cases Alexander Babai 3 years ago
2 changed file(s) with 161 addition(s) and 57 deletion(s). Raw diff Collapse all Expand all
11
22 import (
33 "context"
4 "strconv"
45
56 "github.com/opentracing/opentracing-go"
6 "github.com/opentracing/opentracing-go/ext"
7 otext "github.com/opentracing/opentracing-go/ext"
8 otlog "github.com/opentracing/opentracing-go/log"
79
810 "github.com/go-kit/kit/endpoint"
11 "github.com/go-kit/kit/sd/lb"
912 )
1013
1114 // TraceEndpoint returns a Middleware that wraps the `next` Endpoint in an
2326 }
2427
2528 return func(next endpoint.Endpoint) endpoint.Endpoint {
26 return func(ctx context.Context, request interface{}) (interface{}, error) {
29 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
2730 if cfg.GetOperationName != nil {
2831 if newOperationName := cfg.GetOperationName(ctx, operationName); newOperationName != "" {
2932 operationName = newOperationName
4952
5053 ctx = opentracing.ContextWithSpan(ctx, span)
5154
52 response, err := next(ctx, request)
53 if err := identifyError(response, err, cfg.IgnoreBusinessError); err != nil {
54 ext.LogError(span, err)
55 }
55 defer func() {
56 if err != nil {
57 if lbErr, ok := err.(lb.RetryError); ok {
58 // handle errors originating from lb.Retry
59 fields := make([]otlog.Field, 0, len(lbErr.RawErrors))
60 for idx, rawErr := range lbErr.RawErrors {
61 fields = append(fields, otlog.String(
62 "gokit.retry.error."+strconv.Itoa(idx+1), rawErr.Error(),
63 ))
64 }
5665
57 return response, err
66 otext.LogError(span, lbErr, fields...)
67
68 return
69 }
70
71 // generic error
72 otext.LogError(span, err)
73
74 return
75 }
76
77 // test for business error
78 if res, ok := response.(endpoint.Failer); ok && res.Failed() != nil {
79 span.LogFields(
80 otlog.String("gokit.business.error", res.Failed().Error()),
81 )
82
83 if cfg.IgnoreBusinessError {
84 return
85 }
86
87 // treating business error as real error in span.
88 otext.LogError(span, res.Failed())
89
90 return
91 }
92 }()
93
94 return next(ctx, request)
5895 }
5996 }
6097 }
63100 // OpenTracing Span called `operationName` with server span.kind tag..
64101 func TraceServer(tracer opentracing.Tracer, operationName string, opts ...EndpointOption) endpoint.Middleware {
65102 opts = append(opts, WithTags(map[string]interface{}{
66 ext.SpanKindRPCServer.Key: ext.SpanKindRPCServer.Value,
103 otext.SpanKindRPCServer.Key: otext.SpanKindRPCServer.Value,
67104 }))
68105
69106 return TraceEndpoint(tracer, operationName, opts...)
73110 // OpenTracing Span called `operationName` with client span.kind tag.
74111 func TraceClient(tracer opentracing.Tracer, operationName string, opts ...EndpointOption) endpoint.Middleware {
75112 opts = append(opts, WithTags(map[string]interface{}{
76 ext.SpanKindRPCServer.Key: ext.SpanKindRPCClient.Value,
113 otext.SpanKindRPCClient.Key: otext.SpanKindRPCClient.Value,
77114 }))
78115
79116 return TraceEndpoint(tracer, operationName, opts...)
84121 span.SetTag(key, value)
85122 }
86123 }
87
88 func identifyError(response interface{}, err error, ignoreBusinessError bool) error {
89 if err != nil {
90 return err
91 }
92
93 if !ignoreBusinessError {
94 if res, ok := response.(endpoint.Failer); ok {
95 return res.Failed()
96 }
97 }
98
99 return nil
100 }
33 "context"
44 "errors"
55 "fmt"
6 "reflect"
67 "testing"
8 "time"
79
810 "github.com/opentracing/opentracing-go"
9 "github.com/opentracing/opentracing-go/ext"
11 otext "github.com/opentracing/opentracing-go/ext"
12 otlog "github.com/opentracing/opentracing-go/log"
1013 "github.com/opentracing/opentracing-go/mocktracer"
1114
1215 "github.com/go-kit/kit/endpoint"
16 "github.com/go-kit/kit/sd"
17 "github.com/go-kit/kit/sd/lb"
1318 kitot "github.com/go-kit/kit/tracing/opentracing"
1419 )
1520
2126 span5 = "SPAN-5"
2227 span6 = "SPAN-6"
2328 span7 = "SPAN-7"
29 span8 = "SPAN-8"
2430 )
2531
2632 var (
114120 })
115121 _, _ = tracedEndpoint(context.Background(), struct{}{})
116122
117 // span 3 with disabled IgnoreBusinessError option
123 // span 3 with lb error
118124 mw = kitot.TraceEndpoint(
119125 tracer,
120126 span3,
127 kitot.WithOptions(kitot.EndpointOptions{}),
128 )
129 tracedEndpoint = mw(
130 lb.Retry(
131 5,
132 1*time.Second,
133 lb.NewRoundRobin(
134 sd.FixedEndpointer{
135 func(context.Context, interface{}) (interface{}, error) {
136 return nil, err1
137 },
138 },
139 ),
140 ),
141 )
142 _, _ = tracedEndpoint(context.Background(), struct{}{})
143
144 // span 4 with disabled IgnoreBusinessError option
145 mw = kitot.TraceEndpoint(
146 tracer,
147 span4,
121148 kitot.WithIgnoreBusinessError(false),
122149 )
123150 tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
127154 })
128155 _, _ = tracedEndpoint(context.Background(), struct{}{})
129156
130 // span 4 with enabled IgnoreBusinessError option
131 mw = kitot.TraceEndpoint(tracer, span4, kitot.WithIgnoreBusinessError(true))
157 // span 5 with enabled IgnoreBusinessError option
158 mw = kitot.TraceEndpoint(tracer, span5, kitot.WithIgnoreBusinessError(true))
132159 tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
133160 return failedResponse{
134161 err: err3,
136163 })
137164 _, _ = tracedEndpoint(context.Background(), struct{}{})
138165
139 // span 5 with OperationNameFunc option
140 mw = kitot.TraceEndpoint(
141 tracer,
142 span5,
166 // span 6 with OperationNameFunc option
167 mw = kitot.TraceEndpoint(
168 tracer,
169 span6,
143170 kitot.WithOperationNameFunc(func(ctx context.Context, name string) string {
144171 return fmt.Sprintf("%s-%s", "new", name)
145172 }),
147174 tracedEndpoint = mw(endpoint.Nop)
148175 _, _ = tracedEndpoint(context.Background(), struct{}{})
149176
150 // span 6 with Tags options
151 mw = kitot.TraceEndpoint(
152 tracer,
153 span6,
154 kitot.WithTags(map[string]interface{}{
155 "tag1": "tag1",
156 "tag2": "tag2",
157 }),
158 kitot.WithTags(map[string]interface{}{
159 "tag3": "tag3",
160 }),
161 )
162 tracedEndpoint = mw(endpoint.Nop)
163 _, _ = tracedEndpoint(context.Background(), struct{}{})
164
165 // span 7 with TagsFunc options
177 // span 7 with Tags options
166178 mw = kitot.TraceEndpoint(
167179 tracer,
168180 span7,
173185 kitot.WithTags(map[string]interface{}{
174186 "tag3": "tag3",
175187 }),
188 )
189 tracedEndpoint = mw(endpoint.Nop)
190 _, _ = tracedEndpoint(context.Background(), struct{}{})
191
192 // span 8 with TagsFunc options
193 mw = kitot.TraceEndpoint(
194 tracer,
195 span8,
196 kitot.WithTags(map[string]interface{}{
197 "tag1": "tag1",
198 "tag2": "tag2",
199 }),
200 kitot.WithTags(map[string]interface{}{
201 "tag3": "tag3",
202 }),
176203 kitot.WithTagsFunc(func(ctx context.Context) opentracing.Tags {
177204 return map[string]interface{}{
178205 "tag4": "tag4",
183210 _, _ = tracedEndpoint(context.Background(), struct{}{})
184211
185212 finishedSpans := tracer.FinishedSpans()
186 if want, have := 7, len(finishedSpans); want != have {
213 if want, have := 8, len(finishedSpans); want != have {
187214 t.Fatalf("Want %v span(s), found %v", want, have)
188215 }
189216
216243 t.Fatalf("Want %v, have %v", want, have)
217244 }
218245
246 if want, have := 1, len(span.Logs()); want != have {
247 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
248 }
249
250 if want, have := []otlog.Field{
251 otlog.String("event", "error"),
252 otlog.String("error.object", "some error (previously: some error; some error; some error; some error)"),
253 otlog.String("gokit.retry.error.1", "some error"),
254 otlog.String("gokit.retry.error.2", "some error"),
255 otlog.String("gokit.retry.error.3", "some error"),
256 otlog.String("gokit.retry.error.4", "some error"),
257 otlog.String("gokit.retry.error.5", "some error"),
258 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
259 t.Fatalf("Want %q, have %q", want, have)
260 }
261
219262 // test span 4
220263 span = finishedSpans[3]
221264
223266 t.Fatalf("Want %q, have %q", want, have)
224267 }
225268
226 if want, have := (interface{})(nil), span.Tag("error"); want != have {
269 if want, have := true, span.Tag("error"); want != have {
270 t.Fatalf("Want %v, have %v", want, have)
271 }
272
273 if want, have := 2, len(span.Logs()); want != have {
274 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
275 }
276
277 if want, have := []otlog.Field{
278 otlog.String("gokit.business.error", "some business error"),
279 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
280 t.Fatalf("Want %q, have %q", want, have)
281 }
282
283 if want, have := []otlog.Field{
284 otlog.String("event", "error"),
285 otlog.String("error.object", "some business error"),
286 }, span.Logs()[1].Fields; reflect.DeepEqual(want, have) {
227287 t.Fatalf("Want %q, have %q", want, have)
228288 }
229289
230290 // test span 5
231291 span = finishedSpans[4]
232292
233 if want, have := fmt.Sprintf("%s-%s", "new", span5), span.OperationName; want != have {
293 if want, have := span5, span.OperationName; want != have {
294 t.Fatalf("Want %q, have %q", want, have)
295 }
296
297 if want, have := (interface{})(nil), span.Tag("error"); want != have {
298 t.Fatalf("Want %q, have %q", want, have)
299 }
300
301 if want, have := 1, len(span.Logs()); want != have {
302 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
303 }
304
305 if want, have := []otlog.Field{
306 otlog.String("gokit.business.error", "some business error"),
307 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
234308 t.Fatalf("Want %q, have %q", want, have)
235309 }
236310
237311 // test span 6
238312 span = finishedSpans[5]
239313
240 if want, have := span6, span.OperationName; want != have {
314 if want, have := fmt.Sprintf("%s-%s", "new", span6), span.OperationName; want != have {
315 t.Fatalf("Want %q, have %q", want, have)
316 }
317
318 // test span 7
319 span = finishedSpans[6]
320
321 if want, have := span7, span.OperationName; want != have {
241322 t.Fatalf("Want %q, have %q", want, have)
242323 }
243324
249330 t.Fatalf("Want %q, have %q", want, have)
250331 }
251332
252 // test span 7
253 span = finishedSpans[6]
254
255 if want, have := span7, span.OperationName; want != have {
333 // test span 8
334 span = finishedSpans[7]
335
336 if want, have := span8, span.OperationName; want != have {
256337 t.Fatalf("Want %q, have %q", want, have)
257338 }
258339
288369 }
289370
290371 if want, have := map[string]interface{}{
291 ext.SpanKindRPCServer.Key: ext.SpanKindRPCServer.Value,
372 otext.SpanKindRPCServer.Key: otext.SpanKindRPCServer.Value,
292373 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
293374 t.Fatalf("Want %q, have %q", want, have)
294375 }
316397 }
317398
318399 if want, have := map[string]interface{}{
319 ext.SpanKindRPCClient.Key: ext.SpanKindRPCClient.Value,
400 otext.SpanKindRPCClient.Key: otext.SpanKindRPCClient.Value,
320401 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
321402 t.Fatalf("Want %q, have %q", want, have)
322403 }