From aa426e000851df619dc268f33ca2e013a1a663ab Mon Sep 17 00:00:00 2001 From: Thomas Lokshall Date: Mon, 23 Oct 2023 12:28:37 +0200 Subject: [PATCH] fix: handle nil operation in context on parsing errors (#74) * fix: handle server errors that do not set the operation field in the context * use correct parameter order fot span name assertion --- tracer.go | 13 +++++++++++-- tracer_test.go | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tracer.go b/tracer.go index c4d0f17..e596a1e 100644 --- a/tracer.go +++ b/tracer.go @@ -48,15 +48,21 @@ func (t Tracer) InterceptResponse(ctx context.Context, next graphql.ResponseHand return next(ctx) } oc := graphql.GetOperationContext(ctx) + operationName := oc.OperationName + if oc.Operation != nil && oc.Operation.Name != "" { + operationName = oc.Operation.Name + } operationType := getOperationTypeAttribute(oc) - spanName := makeSpanName(oc.Operation.Name, operationType.Value.AsString()) + spanName := makeSpanName(operationName, operationType.Value.AsString()) ctx, span := t.getTracer(ctx).Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(baseAttributes...)) defer span.End() span.SetAttributes( - semconv.GraphqlOperationName(oc.Operation.Name), operationType, semconv.GraphqlDocument(oc.RawQuery), ) + if operationName != "" { + span.SetAttributes(semconv.GraphqlOperationName(oc.Operation.Name)) + } if stats := extension.GetComplexityStats(ctx); stats != nil { span.SetAttributes(graphqlComplexity.Int(stats.Complexity)) } @@ -128,6 +134,9 @@ func makeSpanName(operationName, operationType string) string { } func getOperationTypeAttribute(oc *graphql.OperationContext) attribute.KeyValue { + if oc.Operation == nil { + return attribute.String("", "") + } switch oc.Operation.Operation { case ast.Mutation: return semconv.GraphqlOperationTypeMutation diff --git a/tracer_test.go b/tracer_test.go index 056a36a..4150a1f 100644 --- a/tracer_test.go +++ b/tracer_test.go @@ -10,6 +10,7 @@ import ( "github.com/zhevron/gqlgen-opentelemetry/v2/testserver" "github.com/zhevron/gqlgen-opentelemetry/v2/testserver/generated" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.20.0" @@ -109,6 +110,20 @@ func (s *TracerSuite) TestQuery_WithFieldSpans_Alias() { s.Require().Equal(fieldAlias.Value.AsString(), "myGreeting") } +func (s *TracerSuite) TestQuery_ParsingError() { + c := s.createTestClient(&Tracer{}) + + query := "query GetGreeting { greeting" + var res struct{ Greeting string } + s.Require().Error(c.Post(query, &res)) + + spans := s.Exporter.GetSpans() + s.Require().Len(spans, 1) + s.Require().Equal("GraphQL Operation", spans[0].Name) + s.Require().Equal(codes.Error, spans[0].Status.Code) + s.Require().Len(spans[0].Attributes, 3) +} + func (s *TracerSuite) TestMutation_SpanCreated() { c := s.createTestClient(&Tracer{})