/
tracer.go
109 lines (86 loc) · 2.86 KB
/
tracer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Base on https://github.com/99designs/gqlgen-contrib/blob/master/gqlopentracing/tracer.go,
// contains the following modifications:
// - shortens the name of the span created in StartOperationExecution method
// - full graphQL query is stored in graphQL.query span tag
package tracing
import (
"context"
"fmt"
"github.com/99designs/gqlgen/graphql"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/opentracing/opentracing-go/log"
"strings"
)
var _ graphql.Tracer = (tracerImpl)(0)
// New returns Tracer for OpenTracing.
// see https://opentracing.io/
func New() graphql.Tracer {
return tracerImpl(0)
}
type tracerImpl int
func (impl *tracerImpl) getSpanName(rawQuery string) string {
index := strings.Index(rawQuery, "(")
if index < 1 {
return rawQuery
}
return rawQuery[:index]
}
func (impl tracerImpl) StartOperationParsing(ctx context.Context) context.Context {
return ctx
}
func (tracerImpl) EndOperationParsing(ctx context.Context) {
}
func (tracerImpl) StartOperationValidation(ctx context.Context) context.Context {
return ctx
}
func (tracerImpl) EndOperationValidation(ctx context.Context) {
}
func (impl tracerImpl) StartOperationExecution(ctx context.Context) context.Context {
requestContext := graphql.GetRequestContext(ctx)
spanName := impl.getSpanName(requestContext.RawQuery)
span, ctx := opentracing.StartSpanFromContext(ctx, spanName)
span.SetTag("graphQL.query", requestContext.RawQuery)
ext.SpanKind.Set(span, "server")
ext.Component.Set(span, "graphQL")
return ctx
}
func (tracerImpl) StartFieldExecution(ctx context.Context, field graphql.CollectedField) context.Context {
span, ctx := opentracing.StartSpanFromContext(ctx, "unnamed")
ext.SpanKind.Set(span, "server")
ext.Component.Set(span, "graphQL")
return ctx
}
func (tracerImpl) StartFieldResolverExecution(ctx context.Context, rc *graphql.ResolverContext) context.Context {
span := opentracing.SpanFromContext(ctx)
span.SetOperationName(rc.Object + "_" + rc.Field.Name)
span.SetTag("resolver.object", rc.Object)
span.SetTag("resolver.field", rc.Field.Name)
return ctx
}
func (tracerImpl) StartFieldChildExecution(ctx context.Context) context.Context {
return ctx
}
func (tracerImpl) EndFieldExecution(ctx context.Context) {
span := opentracing.SpanFromContext(ctx)
defer span.Finish()
rc := graphql.GetResolverContext(ctx)
reqCtx := graphql.GetRequestContext(ctx)
errList := reqCtx.GetErrors(rc)
if len(errList) != 0 {
ext.Error.Set(span, true)
span.LogFields(
log.String("event", "error"),
)
for idx, err := range errList {
span.LogFields(
log.String(fmt.Sprintf("error.%d.message", idx), err.Error()),
log.String(fmt.Sprintf("error.%d.kind", idx), fmt.Sprintf("%T", err)),
)
}
}
}
func (tracerImpl) EndOperationExecution(ctx context.Context) {
span := opentracing.SpanFromContext(ctx)
defer span.Finish()
}