Skip to content

Commit 6af81f1

Browse files
committed
Initial instrumentation
1 parent 47aca28 commit 6af81f1

File tree

4 files changed

+204
-0
lines changed

4 files changed

+204
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
module github.com/signalfx/splunk-otel-go/instrumentation/github.com/graph-gophers/graphql-go/splunkgraphql
22

33
go 1.16
4+
5+
require (
6+
github.com/graph-gophers/graphql-go v1.2.0
7+
github.com/signalfx/splunk-otel-go v0.0.0-00010101000000-000000000000
8+
go.opentelemetry.io/otel v1.2.0
9+
go.opentelemetry.io/otel/trace v1.2.0
10+
)
11+
12+
replace github.com/signalfx/splunk-otel-go => ../../../../../
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
4+
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
5+
github.com/graph-gophers/graphql-go v1.2.0 h1:j3tCG0UcE+3f84OAw/4/6YQKyTr+r0yuUKtnxiu5OH4=
6+
github.com/graph-gophers/graphql-go v1.2.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
7+
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
8+
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
9+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
10+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
11+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
12+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
13+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
14+
go.opentelemetry.io/contrib/propagators/b3 v1.2.0/go.mod h1:kO8hNKCfa1YmQJ0lM7pzfJGvbXEipn/S7afbOfaw2Kc=
15+
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
16+
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
17+
go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E=
18+
go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U=
19+
go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0=
20+
go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0=
21+
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
24+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
25+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright Splunk Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package splunkgraphql provides OpenTelemetry instrumentation for the
16+
// github.com/graph-gophers/graphql-go module.
17+
package splunkgraphql
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/graph-gophers/graphql-go/errors"
24+
"github.com/graph-gophers/graphql-go/introspection"
25+
"github.com/graph-gophers/graphql-go/trace"
26+
"github.com/signalfx/splunk-otel-go/instrumentation/internal"
27+
"go.opentelemetry.io/otel/attribute"
28+
"go.opentelemetry.io/otel/codes"
29+
oteltrace "go.opentelemetry.io/otel/trace"
30+
)
31+
32+
const instrumentationName = "github.com/signalfx/splunk-otel-go/instrumentation/github.com/graph-gophers/graphql-go/splunkgraphql"
33+
34+
var (
35+
graphqlFieldKey = attribute.Key("graphql.field")
36+
graphqlQueryKey = attribute.Key("graphql.query")
37+
graphqlTypeKey = attribute.Key("graphql.type")
38+
)
39+
40+
// otelTracer implements the graphql-go/trace.Tracer interface using
41+
// OpenTelemetry.
42+
type otelTracer struct {
43+
cfg internal.Config
44+
}
45+
46+
var (
47+
_ trace.Tracer = (*otelTracer)(nil)
48+
_ trace.ValidationTracerContext = (*otelTracer)(nil)
49+
)
50+
51+
// NewTracer returns a new trace.Tracer backed by OpenTelemetry.
52+
func NewTracer(opts ...Option) trace.Tracer {
53+
cfg := internal.NewConfig(instrumentationName, localToInternal(opts)...)
54+
return &otelTracer{cfg: *cfg}
55+
}
56+
57+
func traceQueryFinishFunc(span oteltrace.Span) trace.TraceQueryFinishFunc {
58+
return func(errs []*errors.QueryError) {
59+
for _, err := range errs {
60+
span.RecordError(err)
61+
}
62+
switch n := len(errs); n {
63+
case 0:
64+
// Nothing to do.
65+
case 1:
66+
span.SetStatus(codes.Error, errs[0].Error())
67+
default:
68+
msg := fmt.Sprintf("%s (and %d more errors)", errs[0], n-1)
69+
span.SetStatus(codes.Error, msg)
70+
}
71+
span.End()
72+
}
73+
}
74+
75+
// TraceQuery traces a GraphQL query.
76+
func (t *otelTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, trace.TraceQueryFinishFunc) {
77+
spanCtx, span := t.cfg.ResolveTracer(ctx).Start(
78+
ctx,
79+
"GraphQL request",
80+
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
81+
oteltrace.WithAttributes(graphqlQueryKey.String(queryString)),
82+
)
83+
84+
return spanCtx, traceQueryFinishFunc(span)
85+
}
86+
87+
// TraceField traces a GraphQL field access.
88+
func (t *otelTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, trace.TraceFieldFinishFunc) {
89+
if trivial {
90+
return ctx, func(*errors.QueryError) {}
91+
}
92+
93+
spanCtx, span := t.cfg.ResolveTracer(ctx).Start(
94+
ctx,
95+
"GraphQL field",
96+
oteltrace.WithAttributes(
97+
graphqlFieldKey.String(fieldName),
98+
graphqlTypeKey.String(typeName),
99+
),
100+
)
101+
102+
return spanCtx, func(err *errors.QueryError) {
103+
if err != nil {
104+
span.RecordError(err)
105+
span.SetStatus(codes.Error, err.Error())
106+
}
107+
span.End()
108+
}
109+
}
110+
111+
// TraceValidation traces the schema validation step preceding an operation.
112+
func (t *otelTracer) TraceValidation(ctx context.Context) trace.TraceValidationFinishFunc {
113+
_, span := t.cfg.ResolveTracer(ctx).Start(ctx, "GraphQL validation")
114+
return traceQueryFinishFunc(span)
115+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright Splunk Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package splunkgraphql
16+
17+
import (
18+
"go.opentelemetry.io/otel/attribute"
19+
"go.opentelemetry.io/otel/trace"
20+
21+
"github.com/signalfx/splunk-otel-go/instrumentation/internal"
22+
)
23+
24+
func localToInternal(opts []Option) []internal.Option {
25+
out := make([]internal.Option, len(opts))
26+
for i, o := range opts {
27+
out[i] = internal.OptionFunc(func(c *internal.Config) { o.apply(c) })
28+
}
29+
return out
30+
}
31+
32+
// Option applies options to a configuration.
33+
type Option interface {
34+
apply(*internal.Config)
35+
}
36+
37+
type optionConv struct {
38+
iOpt internal.Option
39+
}
40+
41+
func (o optionConv) apply(c *internal.Config) {
42+
o.iOpt.Apply(c)
43+
}
44+
45+
// WithTracerProvider returns an Option that sets the TracerProvider used for
46+
// a configuration.
47+
func WithTracerProvider(tp trace.TracerProvider) Option {
48+
return optionConv{iOpt: internal.WithTracerProvider(tp)}
49+
}
50+
51+
// WithAttributes returns an Option that appends attr to the attributes set
52+
// for every span created.
53+
func WithAttributes(attr []attribute.KeyValue) Option {
54+
return optionConv{iOpt: internal.WithAttributes(attr)}
55+
}

0 commit comments

Comments
 (0)