diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace.rb b/lib/datadog/tracing/contrib/graphql/unified_trace.rb index 166517e17e7..fc3edf569be 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. @@ -268,28 +288,13 @@ 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 => + Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.serialize_error_locations(graphql_error['locations']), @path_key => graphql_error['path'], ) ) 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 serialize_error_locations(locations) - locations.map do |location| - "#{location["line"]}:#{location["column"]}" - end - end end end end diff --git a/sig/datadog/tracing/contrib/graphql/unified_trace.rbs b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs index e23a949034b..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 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..32bf5878bc5 --- /dev/null +++ b/spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'datadog/tracing/contrib/support/spec_helper' +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 } + + 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