From c1310298473c101275672ca904529e1daf0410f8 Mon Sep 17 00:00:00 2001 From: Jakub Martin Date: Mon, 31 Aug 2020 17:08:53 +0200 Subject: [PATCH] Add WithOmitTrivial option. --- contrib/graph-gophers/graphql-go/graphql.go | 3 + .../graph-gophers/graphql-go/graphql_test.go | 122 +++++++++++++----- contrib/graph-gophers/graphql-go/option.go | 8 ++ 3 files changed, 102 insertions(+), 31 deletions(-) diff --git a/contrib/graph-gophers/graphql-go/graphql.go b/contrib/graph-gophers/graphql-go/graphql.go index ef7d05caaa..fb30d9fd88 100644 --- a/contrib/graph-gophers/graphql-go/graphql.go +++ b/contrib/graph-gophers/graphql-go/graphql.go @@ -68,6 +68,9 @@ func (t *Tracer) TraceQuery(ctx context.Context, queryString string, operationNa // TraceField traces a GraphQL field access. func (t *Tracer) TraceField(ctx context.Context, label string, typeName string, fieldName string, trivial bool, args map[string]interface{}) (context.Context, trace.TraceFieldFinishFunc) { + if t.cfg.omitTrivial && trivial { + return ctx, func(queryError *errors.QueryError) {} + } opts := []ddtrace.StartSpanOption{ tracer.ServiceName(t.cfg.serviceName), tracer.Tag(tagGraphqlField, fieldName), diff --git a/contrib/graph-gophers/graphql-go/graphql_test.go b/contrib/graph-gophers/graphql-go/graphql_test.go index f9d8df5809..c8e5dad71f 100644 --- a/contrib/graph-gophers/graphql-go/graphql_test.go +++ b/contrib/graph-gophers/graphql-go/graphql_test.go @@ -21,7 +21,8 @@ import ( type testResolver struct{} -func (*testResolver) Hello() string { return "Hello, world!" } +func (*testResolver) Hello() string { return "Hello, world!" } +func (*testResolver) HelloNonTrivial() (string, error) { return "Hello, world!", nil } func Test(t *testing.T) { s := ` @@ -30,44 +31,103 @@ func Test(t *testing.T) { } type Query { hello: String! + helloNonTrivial: String! } ` - schema := graphql.MustParseSchema(s, new(testResolver), - graphql.Tracer(NewTracer(WithServiceName("test-graphql-service")))) - srv := httptest.NewServer(&relay.Handler{Schema: schema}) - defer srv.Close() + makeRequest := func(opts ...Option) { + opts = append(opts, WithServiceName("test-graphql-service")) - mt := mocktracer.Start() - defer mt.Stop() + schema := graphql.MustParseSchema(s, new(testResolver), + graphql.Tracer(NewTracer(opts...))) + srv := httptest.NewServer(&relay.Handler{Schema: schema}) + defer srv.Close() - http.Post(srv.URL, "application/json", strings.NewReader(`{ - "query": "query TestQuery() { hello }", + http.Post(srv.URL, "application/json", strings.NewReader(`{ + "query": "query TestQuery() { hello, helloNonTrivial }", "operationName": "TestQuery" }`)) - - spans := mt.FinishedSpans() - assert.Len(t, spans, 2) - assert.Equal(t, spans[1].TraceID(), spans[0].TraceID()) - - { - s := spans[0] - assert.Equal(t, "hello", s.Tag(tagGraphqlField)) - assert.Nil(t, s.Tag(ext.Error)) - assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) - assert.Equal(t, "Query", s.Tag(tagGraphqlType)) - assert.Equal(t, "graphql.field", s.OperationName()) - assert.Equal(t, "graphql.field", s.Tag(ext.ResourceName)) } - { - s := spans[1] - assert.Equal(t, "query TestQuery() { hello }", s.Tag(tagGraphqlQuery)) - assert.Equal(t, "TestQuery", s.Tag(tagGraphqlOperationName)) - assert.Nil(t, s.Tag(ext.Error)) - assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) - assert.Equal(t, "graphql.request", s.OperationName()) - assert.Equal(t, "graphql.request", s.Tag(ext.ResourceName)) - } + t.Run("defaults", func(t *testing.T) { + mt := mocktracer.Start() + defer mt.Stop() + + makeRequest() + + spans := mt.FinishedSpans() + assert.Len(t, spans, 3) + assert.Equal(t, spans[1].TraceID(), spans[0].TraceID()) + assert.Equal(t, spans[2].TraceID(), spans[0].TraceID()) + + // The order of the spans isn't deterministic. + helloSpanIndex := 0 + helloNonTrivialSpanIndex := 1 + if spans[0].Tag(tagGraphqlField) == "helloNonTrivial" { + helloNonTrivialSpanIndex = 0 + helloSpanIndex = 1 + } + + { + s := spans[helloNonTrivialSpanIndex] + assert.Equal(t, "helloNonTrivial", s.Tag(tagGraphqlField)) + assert.Nil(t, s.Tag(ext.Error)) + assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) + assert.Equal(t, "Query", s.Tag(tagGraphqlType)) + assert.Equal(t, "graphql.field", s.OperationName()) + assert.Equal(t, "graphql.field", s.Tag(ext.ResourceName)) + } + + { + s := spans[helloSpanIndex] + assert.Equal(t, "hello", s.Tag(tagGraphqlField)) + assert.Nil(t, s.Tag(ext.Error)) + assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) + assert.Equal(t, "Query", s.Tag(tagGraphqlType)) + assert.Equal(t, "graphql.field", s.OperationName()) + assert.Equal(t, "graphql.field", s.Tag(ext.ResourceName)) + } + + { + s := spans[2] + assert.Equal(t, "query TestQuery() { hello, helloNonTrivial }", s.Tag(tagGraphqlQuery)) + assert.Equal(t, "TestQuery", s.Tag(tagGraphqlOperationName)) + assert.Nil(t, s.Tag(ext.Error)) + assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) + assert.Equal(t, "graphql.request", s.OperationName()) + assert.Equal(t, "graphql.request", s.Tag(ext.ResourceName)) + } + }) + + t.Run("WithOmitTrivial", func(t *testing.T) { + mt := mocktracer.Start() + defer mt.Stop() + + makeRequest(WithOmitTrivial()) + + spans := mt.FinishedSpans() + assert.Len(t, spans, 2) + assert.Equal(t, spans[1].TraceID(), spans[0].TraceID()) + + { + s := spans[0] + assert.Equal(t, "helloNonTrivial", s.Tag(tagGraphqlField)) + assert.Nil(t, s.Tag(ext.Error)) + assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) + assert.Equal(t, "Query", s.Tag(tagGraphqlType)) + assert.Equal(t, "graphql.field", s.OperationName()) + assert.Equal(t, "graphql.field", s.Tag(ext.ResourceName)) + } + + { + s := spans[1] + assert.Equal(t, "query TestQuery() { hello, helloNonTrivial }", s.Tag(tagGraphqlQuery)) + assert.Equal(t, "TestQuery", s.Tag(tagGraphqlOperationName)) + assert.Nil(t, s.Tag(ext.Error)) + assert.Equal(t, "test-graphql-service", s.Tag(ext.ServiceName)) + assert.Equal(t, "graphql.request", s.OperationName()) + assert.Equal(t, "graphql.request", s.Tag(ext.ResourceName)) + } + }) } func TestAnalyticsSettings(t *testing.T) { diff --git a/contrib/graph-gophers/graphql-go/option.go b/contrib/graph-gophers/graphql-go/option.go index d6267e57a9..d9909c622a 100644 --- a/contrib/graph-gophers/graphql-go/option.go +++ b/contrib/graph-gophers/graphql-go/option.go @@ -15,6 +15,7 @@ import ( type config struct { serviceName string analyticsRate float64 + omitTrivial bool } // Option represents an option that can be used customize the Tracer. @@ -62,3 +63,10 @@ func WithAnalyticsRate(rate float64) Option { } } } + +// WithOmitTrivial enables omission of graphql fields marked as trivial. +func WithOmitTrivial() Option { + return func(cfg *config) { + cfg.omitTrivial = true + } +}