Skip to content

Commit bd703c2

Browse files
authored
Merge pull request #411 from dackroyd/trace-validation-context
Add context to validation tracing
2 parents 6859f27 + 1a55b96 commit bd703c2

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

graphql.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,23 @@ import (
2525
// resolver, then the schema can not be executed, but it may be inspected (e.g. with ToJSON).
2626
func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (*Schema, error) {
2727
s := &Schema{
28-
schema: schema.New(),
29-
maxParallelism: 10,
30-
tracer: trace.OpenTracingTracer{},
31-
validationTracer: trace.NoopValidationTracer{},
32-
logger: &log.DefaultLogger{},
28+
schema: schema.New(),
29+
maxParallelism: 10,
30+
tracer: trace.OpenTracingTracer{},
31+
logger: &log.DefaultLogger{},
3332
}
3433
for _, opt := range opts {
3534
opt(s)
3635
}
3736

37+
if s.validationTracer == nil {
38+
if tracer, ok := s.tracer.(trace.ValidationTracerContext); ok {
39+
s.validationTracer = tracer
40+
} else {
41+
s.validationTracer = &validationBridgingTracer{tracer: trace.NoopValidationTracer{}}
42+
}
43+
}
44+
3845
if err := s.schema.Parse(schemaString, s.useStringDescriptions); err != nil {
3946
return nil, err
4047
}
@@ -68,7 +75,7 @@ type Schema struct {
6875
maxDepth int
6976
maxParallelism int
7077
tracer trace.Tracer
71-
validationTracer trace.ValidationTracer
78+
validationTracer trace.ValidationTracerContext
7279
logger log.Logger
7380
useStringDescriptions bool
7481
disableIntrospection bool
@@ -117,9 +124,10 @@ func Tracer(tracer trace.Tracer) SchemaOpt {
117124
}
118125

119126
// ValidationTracer is used to trace validation errors. It defaults to trace.NoopValidationTracer.
127+
// Deprecated: context is needed to support tracing correctly. Use a Tracer which implements trace.ValidationTracerContext.
120128
func ValidationTracer(tracer trace.ValidationTracer) SchemaOpt {
121129
return func(s *Schema) {
122-
s.validationTracer = tracer
130+
s.validationTracer = &validationBridgingTracer{tracer: tracer}
123131
}
124132
}
125133

@@ -186,7 +194,7 @@ func (s *Schema) exec(ctx context.Context, queryString string, operationName str
186194
return &Response{Errors: []*errors.QueryError{qErr}}
187195
}
188196

189-
validationFinish := s.validationTracer.TraceValidation()
197+
validationFinish := s.validationTracer.TraceValidation(ctx)
190198
errs := validation.Validate(s.schema, doc, variables, s.maxDepth)
191199
validationFinish(errs)
192200
if len(errs) != 0 {
@@ -272,6 +280,14 @@ func (s *Schema) validateSchema() error {
272280
return nil
273281
}
274282

283+
type validationBridgingTracer struct {
284+
tracer trace.ValidationTracer
285+
}
286+
287+
func (t *validationBridgingTracer) TraceValidation(context.Context) trace.TraceValidationFinishFunc {
288+
return t.tracer.TraceValidation()
289+
}
290+
275291
func validateRootOp(s *schema.Schema, name string, mandatory bool) error {
276292
t, ok := s.EntryPoints[name]
277293
if !ok {

subscriptions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (s *Schema) subscribe(ctx context.Context, queryString string, operationNam
3636
return sendAndReturnClosed(&Response{Errors: []*qerrors.QueryError{qErr}})
3737
}
3838

39-
validationFinish := s.validationTracer.TraceValidation()
39+
validationFinish := s.validationTracer.TraceValidation(ctx)
4040
errs := validation.Validate(s.schema, doc, variables, s.maxDepth)
4141
validationFinish(errs)
4242
if len(errs) != 0 {

trace/trace.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ func (OpenTracingTracer) TraceField(ctx context.Context, label, typeName, fieldN
6767
}
6868
}
6969

70+
func (OpenTracingTracer) TraceValidation(ctx context.Context) TraceValidationFinishFunc {
71+
span, _ := opentracing.StartSpanFromContext(ctx, "Validate Query")
72+
73+
return func(errs []*errors.QueryError) {
74+
if len(errs) > 0 {
75+
msg := errs[0].Error()
76+
if len(errs) > 1 {
77+
msg += fmt.Sprintf(" (and %d more errors)", len(errs)-1)
78+
}
79+
ext.Error.Set(span, true)
80+
span.SetTag("graphql.error", msg)
81+
}
82+
span.Finish()
83+
}
84+
}
85+
7086
func noop(*errors.QueryError) {}
7187

7288
type NoopTracer struct{}

trace/validation_trace.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
package trace
22

33
import (
4+
"context"
5+
46
"github.com/graph-gophers/graphql-go/errors"
57
)
68

79
type TraceValidationFinishFunc = TraceQueryFinishFunc
810

11+
// Deprecated: use ValidationTracerContext.
912
type ValidationTracer interface {
1013
TraceValidation() TraceValidationFinishFunc
1114
}
1215

16+
type ValidationTracerContext interface {
17+
TraceValidation(ctx context.Context) TraceValidationFinishFunc
18+
}
19+
1320
type NoopValidationTracer struct{}
1421

22+
// Deprecated: use a Tracer which implements ValidationTracerContext.
1523
func (NoopValidationTracer) TraceValidation() TraceValidationFinishFunc {
1624
return func(errs []*errors.QueryError) {}
1725
}

0 commit comments

Comments
 (0)