From 169c10f21265c73b5abae0b20c02e6a9b4c8c723 Mon Sep 17 00:00:00 2001 From: Mauro Codella Date: Thu, 6 Nov 2025 09:32:00 +0100 Subject: [PATCH 1/5] fix(graphql): handle nil value for locations in unified_trace --- .../tracing/contrib/graphql/unified_trace.rb | 8 +++- .../tracing/contrib/graphql/unified_trace.rbs | 2 +- .../contrib/graphql/unified_trace_spec.rb | 40 +++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace.rb b/lib/datadog/tracing/contrib/graphql/unified_trace.rb index 166517e17e7..aad88269912 100644 --- a/lib/datadog/tracing/contrib/graphql/unified_trace.rb +++ b/lib/datadog/tracing/contrib/graphql/unified_trace.rb @@ -268,7 +268,7 @@ def add_query_error_events(span, errors) @type_key => parsed_error.type, @stacktrace_key => parsed_error.backtrace, @message_key => graphql_error['message'], - @locations_key => serialize_error_locations(graphql_error['locations']), + @locations_key => self.class.serialize_error_locations(graphql_error['locations']), @path_key => graphql_error['path'], ) ) @@ -285,7 +285,11 @@ def add_query_error_events(span, errors) # ] # is serialized as: # ["3:10", "7:8"] - def serialize_error_locations(locations) + def self.serialize_error_locations(locations) + # locations are only provided by the `graphql` library when the error can + # be associated to a particular point in the query. + return [] if locations.nil? + locations.map do |location| "#{location["line"]}:#{location["column"]}" end diff --git a/sig/datadog/tracing/contrib/graphql/unified_trace.rbs b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs index e23a949034b..60bd8c875c4 100644 --- a/sig/datadog/tracing/contrib/graphql/unified_trace.rbs +++ b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs @@ -99,7 +99,7 @@ module Datadog def add_query_error_events: (SpanOperation span, Array[GraphQL::Error] errors) -> void - def serialize_error_locations: (Array[Hash[String, Integer]] locations) -> Array[String] + def self.serialize_error_locations: (Array[Hash[String, Integer]]? locations) -> Array[String] end end end diff --git a/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb new file mode 100644 index 00000000000..00e0b69be5c --- /dev/null +++ b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'datadog/tracing/contrib/support/spec_helper' +require 'datadog/tracing/contrib/graphql/unified_trace' + +RSpec.describe Datadog::Tracing::Contrib::GraphQL::UnifiedTrace do + describe '.serialize_error_locations' do + subject(:result) { described_class.serialize_error_locations(locations) } + + context 'when locations is nil' do + let(:locations) { nil } + + it 'returns an empty array' do + expect(result).to eq([]) + end + end + + context 'when locations is an array' do + let(:locations) do + [ + { 'line' => 3, 'column' => 10 }, + { 'line' => 7, 'column' => 8 } + ] + end + + it 'maps locations to formatted strings' do + expect(result).to eq(['3:10', '7:8']) + end + end + + context 'when locations is an empty array' do + let(:locations) { [] } + + it 'returns an empty array' do + expect(result).to eq([]) + end + end + end +end + From 565ae85c43eea66a904cc207bf63010166b402be Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 19 Nov 2025 11:41:09 +0000 Subject: [PATCH 2/5] Linting fixes --- .../tracing/contrib/graphql/unified_trace.rb | 40 +++++++++---------- .../contrib/graphql/unified_trace_spec.rb | 5 +-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace.rb b/lib/datadog/tracing/contrib/graphql/unified_trace.rb index aad88269912..30ce3fbca8d 100644 --- a/lib/datadog/tracing/contrib/graphql/unified_trace.rb +++ b/lib/datadog/tracing/contrib/graphql/unified_trace.rb @@ -176,6 +176,26 @@ def platform_resolve_type_key(type, *args, **kwargs) "#{type.graphql_name}.resolve_type" end + # Serialize error's `locations` array as an array of Strings, given + # Span Events do not support hashes nested inside arrays. + # + # Here's an example in which `locations`: + # [ + # {"line" => 3, "column" => 10}, + # {"line" => 7, "column" => 8}, + # ] + # is serialized as: + # ["3:10", "7:8"] + def self.serialize_error_locations(locations) + # locations are only provided by the `graphql` library when the error can + # be associated to a particular point in the query. + return [] if locations.nil? + + locations.map do |location| + "#{location["line"]}:#{location["column"]}" + end + end + private # Traces the given callable with the given trace key, resource, and kwargs. @@ -274,26 +294,6 @@ def add_query_error_events(span, errors) ) end end - - # Serialize error's `locations` array as an array of Strings, given - # Span Events do not support hashes nested inside arrays. - # - # Here's an example in which `locations`: - # [ - # {"line" => 3, "column" => 10}, - # {"line" => 7, "column" => 8}, - # ] - # is serialized as: - # ["3:10", "7:8"] - def self.serialize_error_locations(locations) - # locations are only provided by the `graphql` library when the error can - # be associated to a particular point in the query. - return [] if locations.nil? - - locations.map do |location| - "#{location["line"]}:#{location["column"]}" - end - end end end end diff --git a/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb index 00e0b69be5c..a2f877b4fca 100644 --- a/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb @@ -18,8 +18,8 @@ context 'when locations is an array' do let(:locations) do [ - { 'line' => 3, 'column' => 10 }, - { 'line' => 7, 'column' => 8 } + {'line' => 3, 'column' => 10}, + {'line' => 7, 'column' => 8} ] end @@ -37,4 +37,3 @@ end end end - From 1c74992ce09b5cfc8a346d28b924d4bd1809a1a8 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 19 Nov 2025 11:41:41 +0000 Subject: [PATCH 3/5] Directly access helper method Since the `UnifiedTrace` can get mixed in elsewhere, we must make sure to access the helper module directly by name. --- lib/datadog/tracing/contrib/graphql/unified_trace.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace.rb b/lib/datadog/tracing/contrib/graphql/unified_trace.rb index 30ce3fbca8d..fc3edf569be 100644 --- a/lib/datadog/tracing/contrib/graphql/unified_trace.rb +++ b/lib/datadog/tracing/contrib/graphql/unified_trace.rb @@ -288,7 +288,8 @@ def add_query_error_events(span, errors) @type_key => parsed_error.type, @stacktrace_key => parsed_error.backtrace, @message_key => graphql_error['message'], - @locations_key => self.class.serialize_error_locations(graphql_error['locations']), + @locations_key => + Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.serialize_error_locations(graphql_error['locations']), @path_key => graphql_error['path'], ) ) From 458285c6b58c28c64e7754d4a2522a47a80315fd Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 19 Nov 2025 12:19:25 +0000 Subject: [PATCH 4/5] Avoid running spec on legacy graphql versions --- .../tracing/contrib/graphql/unified_trace_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb index a2f877b4fca..32bf5878bc5 100644 --- a/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb @@ -1,9 +1,16 @@ # frozen_string_literal: true require 'datadog/tracing/contrib/support/spec_helper' -require 'datadog/tracing/contrib/graphql/unified_trace' +require 'graphql' + +RSpec.describe "Datadog::Tracing::Contrib::GraphQL::UnifiedTrace" do + before do + skip 'UnifiedTrace is only supported in GraphQL 2.0.19 and above' if Gem::Version.new(::GraphQL::VERSION) < Gem::Version.new('2.0.19') + require 'datadog/tracing/contrib/graphql/unified_trace' + end + + let(:described_class) { Datadog::Tracing::Contrib::GraphQL::UnifiedTrace } -RSpec.describe Datadog::Tracing::Contrib::GraphQL::UnifiedTrace do describe '.serialize_error_locations' do subject(:result) { described_class.serialize_error_locations(locations) } From d2c02c62d5d54414239797c48311b39c9b84d90e Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 19 Nov 2025 12:44:51 +0000 Subject: [PATCH 5/5] Update sig/datadog/tracing/contrib/graphql/unified_trace.rbs Co-authored-by: Sergey Fedorov --- sig/datadog/tracing/contrib/graphql/unified_trace.rbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sig/datadog/tracing/contrib/graphql/unified_trace.rbs b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs index 60bd8c875c4..4eb264804e7 100644 --- a/sig/datadog/tracing/contrib/graphql/unified_trace.rbs +++ b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs @@ -99,7 +99,7 @@ module Datadog def add_query_error_events: (SpanOperation span, Array[GraphQL::Error] errors) -> void - def self.serialize_error_locations: (Array[Hash[String, Integer]]? locations) -> Array[String] + def self.serialize_error_locations: (::Array[::Hash[::String, ::Integer]]? locations) -> ::Array[::String] end end end