Skip to content

Commit

Permalink
Initial instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlias committed Dec 8, 2021
1 parent 47aca28 commit 76d36b2
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
module github.com/signalfx/splunk-otel-go/instrumentation/github.com/graph-gophers/graphql-go/splunkgraphql

go 1.16

require (
github.com/graph-gophers/graphql-go v1.2.0
github.com/signalfx/splunk-otel-go v0.0.0-00010101000000-000000000000
go.opentelemetry.io/otel v1.2.0
go.opentelemetry.io/otel/trace v1.2.0
)

replace github.com/signalfx/splunk-otel-go => ../../../../../
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/graph-gophers/graphql-go v1.2.0 h1:j3tCG0UcE+3f84OAw/4/6YQKyTr+r0yuUKtnxiu5OH4=
github.com/graph-gophers/graphql-go v1.2.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/contrib/propagators/b3 v1.2.0/go.mod h1:kO8hNKCfa1YmQJ0lM7pzfJGvbXEipn/S7afbOfaw2Kc=
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E=
go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U=
go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0=
go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright Splunk Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package splunkgraphql provides OpenTelemetry instrumentation for the
// github.com/graph-gophers/graphql-go module.
package splunkgraphql

import (
"context"
"fmt"

"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/introspection"
"github.com/graph-gophers/graphql-go/trace"
"github.com/signalfx/splunk-otel-go/instrumentation/internal"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
oteltrace "go.opentelemetry.io/otel/trace"
)

const instrumentationName = "github.com/signalfx/splunk-otel-go/instrumentation/github.com/graph-gophers/graphql-go/splunkgraphql"

type otelTracer struct {
cfg internal.Config
}

var (
_ trace.Tracer = (*otelTracer)(nil)
_ trace.ValidationTracerContext = (*otelTracer)(nil)
)

// NewTracer returns a new trace.Tracer backed by OpenTelemetry.
func NewTracer(opts ...Option) trace.Tracer {
cfg := internal.NewConfig(instrumentationName, localToInternal(opts)...)
return &otelTracer{cfg: *cfg}
}

func traceQueryFinishFunc(span oteltrace.Span) trace.TraceQueryFinishFunc {
return func(errs []*errors.QueryError) {
for _, err := range errs {
span.RecordError(err)
}
if len(errs) > 0 {
msg := fmt.Sprintf("%d validation errors", len(errs))
span.SetStatus(codes.Error, msg)
}
span.End()
}
}

// TraceQuery traces a GraphQL query.
func (t *otelTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, trace.TraceQueryFinishFunc) {
tracer := t.cfg.ResolveTracer(ctx)
spanCtx, span := tracer.Start(ctx, "GraphQL request",
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
)
span.SetAttributes(attribute.String("trace.operation", "request"))
span.SetAttributes(attribute.String("graphql.query", queryString))

if operationName != "" {
span.SetAttributes(attribute.String("graphql.operationName", operationName))
}

return spanCtx, traceQueryFinishFunc(span)
}

// TraceField traces a GraphQL field access.
func (t *otelTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, trace.TraceFieldFinishFunc) {
if trivial {
return ctx, func(*errors.QueryError) {}
}

tracer := t.cfg.ResolveTracer(ctx)
spanCtx, span := tracer.Start(ctx, label)
span.SetAttributes(attribute.String("trace.operation", "field"))
span.SetAttributes(attribute.String("graphql.type", typeName))
span.SetAttributes(attribute.String("graphql.field", fieldName))

return spanCtx, func(err *errors.QueryError) {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}
}

// TraceValidation traces the schema validation step preceding an operation.
func (t *otelTracer) TraceValidation(ctx context.Context) trace.TraceValidationFinishFunc {
tracer := t.cfg.ResolveTracer(ctx)
_, span := tracer.Start(ctx, "Validate query")
span.SetAttributes(attribute.String("trace.operation", "validation"))

return traceQueryFinishFunc(span)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Splunk Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package splunkgraphql

import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

"github.com/signalfx/splunk-otel-go/instrumentation/internal"
)

func localToInternal(opts []Option) []internal.Option {
out := make([]internal.Option, len(opts))
for i, o := range opts {
out[i] = internal.OptionFunc(func(c *internal.Config) { o.apply(c) })
}
return out
}

// Option applies options to a configuration.
type Option interface {
apply(*internal.Config)
}

type optionConv struct {
iOpt internal.Option
}

func (o optionConv) apply(c *internal.Config) {
o.iOpt.Apply(c)
}

// WithTracerProvider returns an Option that sets the TracerProvider used for
// a configuration.
func WithTracerProvider(tp trace.TracerProvider) Option {
return optionConv{iOpt: internal.WithTracerProvider(tp)}
}

// WithAttributes returns an Option that appends attr to the attributes set
// for every span created.
func WithAttributes(attr []attribute.KeyValue) Option {
return optionConv{iOpt: internal.WithAttributes(attr)}
}

0 comments on commit 76d36b2

Please sign in to comment.