Skip to content
39 changes: 22 additions & 17 deletions lib/datadog/tracing/contrib/graphql/unified_trace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/tracing/contrib/graphql/unified_trace.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions spec/datadog/tracing/contrib/graphql/unified_trace_spec.rb
Original file line number Diff line number Diff line change
@@ -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
Loading