diff --git a/Steepfile b/Steepfile index 23076c9885e..83d86357de3 100644 --- a/Steepfile +++ b/Steepfile @@ -595,6 +595,7 @@ target :datadog do library 'opentelemetry-api' library 'passenger' library 'webmock' + library 'graphql' # TODO: gem 'libddwaf' library 'libddwaf' diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index 09033778b31..aab0189e297 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -859,6 +859,7 @@ The `instrument :graphql` method accepts the following parameters. Additional op | ------------------------ | - | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | | `enabled` | `DD_TRACE_GRAPHQL_ENABLED` | `Bool` | Whether the integration should create spans. | `true` | | `schemas` | | `Array` | Array of `GraphQL::Schema` objects (that support class-based schema only) to trace. If you do not provide any, then tracing will applied to all the schemas. | `[]` | +| `with_unified_tracer` | | `Bool` | Enable to instrument with `UnifiedTrace` tracer, enabling support for API Catalog. `with_deprecated_tracer` has priority over this. Default is `false`, using `GraphQL::Tracing::DataDogTrace` (Added in v2.2) | `false` | | `with_deprecated_tracer` | | `Bool` | Enable to instrument with deprecated `GraphQL::Tracing::DataDogTracing`. Default is `false`, using `GraphQL::Tracing::DataDogTrace` | `false` | | `service_name` | | `String` | Service name used for graphql instrumentation | `'ruby-graphql'` | @@ -874,6 +875,14 @@ class YourSchema < GraphQL::Schema end ``` +With `UnifiedTracer` (Added in v2.2) + +```ruby +class YourSchema < GraphQL::Schema + trace_with Datadog::Tracing::Contrib::GraphQL::UnifiedTrace +end +``` + or with `GraphQL::Tracing::DataDogTracing` (deprecated) ```ruby @@ -886,6 +895,23 @@ end Do _NOT_ `instrument :graphql` in `Datadog.configure` if you choose to configure manually, as to avoid double tracing. These two means of configuring GraphQL tracing are considered mutually exclusive. +**Adding custom tags to Datadog spans** + +You can add custom tags to Datadog spans by implementing the `prepare_span` method in a subclass, then manually configuring your schema. + +```ruby +class YourSchema < GraphQL::Schema + module CustomTracing + include Datadog::Tracing::Contrib::GraphQL::UnifiedTrace + def prepare_span(trace_key, data, span) + span.set_tag("custom:#{trace_key}", data.keys.sort.join(",")) + end + end + + trace_with CustomTracing +end +``` + ### gRPC The `grpc` integration adds both client and server interceptors, which run as middleware before executing the service's remote procedure call. As gRPC applications are often distributed, the integration shares trace information between client and server. diff --git a/lib/datadog/tracing/contrib/graphql/configuration/settings.rb b/lib/datadog/tracing/contrib/graphql/configuration/settings.rb index 9f14ec5ee57..f6f5973e191 100644 --- a/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/graphql/configuration/settings.rb @@ -42,6 +42,11 @@ class Settings < Contrib::Configuration::Settings o.type :bool o.default false end + + option :with_unified_tracer do |o| + o.type :bool + o.default false + end end end end diff --git a/lib/datadog/tracing/contrib/graphql/patcher.rb b/lib/datadog/tracing/contrib/graphql/patcher.rb index 26ab0cbd281..b473b999ff5 100644 --- a/lib/datadog/tracing/contrib/graphql/patcher.rb +++ b/lib/datadog/tracing/contrib/graphql/patcher.rb @@ -4,6 +4,7 @@ require_relative '../patcher' require_relative 'tracing_patcher' require_relative 'trace_patcher' +require_relative 'unified_trace_patcher' module Datadog module Tracing @@ -23,10 +24,15 @@ def patch if configuration[:with_deprecated_tracer] TracingPatcher.patch!(schemas, trace_options) elsif Integration.trace_supported? - TracePatcher.patch!(schemas, trace_options) + if configuration[:with_unified_tracer] + UnifiedTracePatcher.patch!(schemas, trace_options) + else + TracePatcher.patch!(schemas, trace_options) + end else Datadog.logger.warn( - "GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace. "\ + "GraphQL version (#{target_version}) does not support GraphQL::Tracing::DataDogTrace"\ + 'or Datadog::Tracing::Contrib::GraphQL::UnifiedTrace.'\ 'Falling back to GraphQL::Tracing::DataDogTracing.' ) TracingPatcher.patch!(schemas, trace_options) diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace.rb b/lib/datadog/tracing/contrib/graphql/unified_trace.rb new file mode 100644 index 00000000000..1f4ba8f73e8 --- /dev/null +++ b/lib/datadog/tracing/contrib/graphql/unified_trace.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +require 'graphql/tracing' + +module Datadog + module Tracing + module Contrib + module GraphQL + # These methods will be called by the GraphQL runtime to trace the execution of queries. + # This tracer differs from the upstream one as it follows the unified naming convention specification, + # which is required to use features such as API Catalog. + # DEV-3.0: This tracer should be the default one in the next major version. + module UnifiedTrace + # @param analytics_enabled [Boolean] Deprecated + # @param analytics_sample_rate [Float] Deprecated + # @param service [String|nil] The service name to be set on the spans + def initialize(*args, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **kwargs) + @analytics_enabled = analytics_enabled + @analytics_sample_rate = analytics_sample_rate + + @service_name = service + @has_prepare_span = respond_to?(:prepare_span) + super + end + + def lex(*args, query_string:, **kwargs) + trace(proc { super }, 'lex', query_string, query_string: query_string) + end + + def parse(*args, query_string:, **kwargs) + trace(proc { super }, 'parse', query_string, query_string: query_string) do |span| + span.set_tag('graphql.source', query_string) + end + end + + def validate(*args, query:, validate:, **kwargs) + trace(proc { super }, 'validate', query.selected_operation_name, query: query, validate: validate) do |span| + span.set_tag('graphql.source', query.query_string) + end + end + + def analyze_multiplex(*args, multiplex:, **kwargs) + trace(proc { super }, 'analyze_multiplex', multiplex_resource(multiplex), multiplex: multiplex) + end + + def analyze_query(*args, query:, **kwargs) + trace(proc { super }, 'analyze', query.query_string, query: query) + end + + def execute_multiplex(*args, multiplex:, **kwargs) + trace(proc { super }, 'execute_multiplex', multiplex_resource(multiplex), multiplex: multiplex) do |span| + span.set_tag('graphql.source', "Multiplex[#{multiplex.queries.map(&:query_string).join(', ')}]") + end + end + + def execute_query(*args, query:, **kwargs) + trace(proc { super }, 'execute', query.selected_operation_name, query: query) do |span| + span.set_tag('graphql.source', query.query_string) + span.set_tag('graphql.operation.type', query.selected_operation.operation_type) + span.set_tag('graphql.operation.name', query.selected_operation_name) if query.selected_operation_name + query.variables.instance_variable_get(:@storage).each do |key, value| + span.set_tag("graphql.variables.#{key}", value) + end + end + end + + def execute_query_lazy(*args, query:, multiplex:, **kwargs) + resource = if query + query.selected_operation_name || fallback_transaction_name(query.context) + else + multiplex_resource(multiplex) + end + trace(proc { super }, 'execute_lazy', resource, query: query, multiplex: multiplex) + end + + def execute_field_span(callable, span_key, **kwargs) + # @platform_key_cache is initialized upstream, in ::GraphQL::Tracing::PlatformTrace + platform_key = @platform_key_cache[UnifiedTrace].platform_field_key_cache[kwargs[:field]] + + if platform_key + trace(callable, span_key, platform_key, **kwargs) do |span| + kwargs[:arguments].each do |key, value| + span.set_tag("graphql.variables.#{key}", value) + end + end + else + callable.call + end + end + + def execute_field(*args, **kwargs) + execute_field_span(proc { super }, 'resolve', **kwargs) + end + + def execute_field_lazy(*args, **kwargs) + execute_field_span(proc { super }, 'resolve_lazy', **kwargs) + end + + def authorized_span(callable, span_key, **kwargs) + platform_key = @platform_key_cache[UnifiedTrace].platform_authorized_key_cache[kwargs[:type]] + trace(callable, span_key, platform_key, **kwargs) + end + + def authorized(*args, **kwargs) + authorized_span(proc { super }, 'authorized', **kwargs) + end + + def authorized_lazy(*args, **kwargs) + authorized_span(proc { super }, 'authorized_lazy', **kwargs) + end + + def resolve_type_span(callable, span_key, **kwargs) + platform_key = @platform_key_cache[UnifiedTrace].platform_resolve_type_key_cache[kwargs[:type]] + trace(callable, span_key, platform_key, **kwargs) + end + + def resolve_type(*args, **kwargs) + resolve_type_span(proc { super }, 'resolve_type', **kwargs) + end + + def resolve_type_lazy(*args, **kwargs) + resolve_type_span(proc { super }, 'resolve_type_lazy', **kwargs) + end + + include ::GraphQL::Tracing::PlatformTrace + + def platform_field_key(field, *args, **kwargs) + field.path + end + + def platform_authorized_key(type, *args, **kwargs) + "#{type.graphql_name}.authorized" + end + + def platform_resolve_type_key(type, *args, **kwargs) + "#{type.graphql_name}.resolve_type" + end + + private + + def trace(callable, trace_key, resource, **kwargs) + Tracing.trace("graphql.#{trace_key}", resource: resource, service: @service_name, type: 'graphql') do |span| + yield(span) if block_given? + + prepare_span(trace_key, kwargs, span) if @has_prepare_span + + callable.call + end + end + + def multiplex_resource(multiplex) + return nil unless multiplex + + operations = multiplex.queries.map(&:selected_operation_name).compact.join(', ') + if operations.empty? + first_query = multiplex.queries.first + fallback_transaction_name(first_query && first_query.context) + else + operations + end + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb b/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb new file mode 100644 index 00000000000..0d3b1d33d79 --- /dev/null +++ b/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Datadog + module Tracing + module Contrib + module GraphQL + # Provides instrumentation for `graphql` through the GraphQL's tracing with methods defined in UnifiedTrace + module UnifiedTracePatcher + module_function + + def patch!(schemas, options) + require_relative 'unified_trace' + if schemas.empty? + ::GraphQL::Schema.trace_with(UnifiedTrace, **options) + else + schemas.each do |schema| + schema.trace_with(UnifiedTrace, **options) + end + end + end + 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 new file mode 100644 index 00000000000..6e4aae46582 --- /dev/null +++ b/sig/datadog/tracing/contrib/graphql/unified_trace.rbs @@ -0,0 +1,76 @@ +module Datadog + module Tracing + module Contrib + module GraphQL + module UnifiedTrace + @analytics_enabled: bool + + @analytics_sample_rate: Float + + @service_name: String? + + @has_prepare_span: bool + def initialize: (?analytics_enabled: bool, ?analytics_sample_rate: Float, ?service: String?, **Hash[Symbol, Object] kwargs) -> self + + type lexerArray = Array[Integer | Symbol | String | nil | lexerArray] + + def lex: (query_string: String) -> lexerArray + + def parse: (query_string: String) -> GraphQL::Language::Nodes::Document + + def validate: (query: GraphQL::Query, validate: bool) -> { remaining_timeout: Float?, error: Array[StandardError] } + + def analyze_multiplex: (multiplex: GraphQL::Execution::Multiplex) -> Array[Object] + + def analyze_query: (query: GraphQL::Query) -> Array[Object] + + def execute_multiplex: (multiplex: GraphQL::Execution::Multiplex) -> Array[GraphQL::Query::Result] + + def execute_query: (query: GraphQL::Query) -> GraphQL::Query::Result + + def execute_query_lazy: (query: GraphQL::Query, multiplex: GraphQL::Execution::Multiplex) -> GraphQL::Query::Result + + type executeFieldKwargs = {query: GraphQL::Query, field: GraphQL::Schema::Field, ast_node: GraphQL::Language::Nodes::Field, arguments: Hash[Symbol, String], object: GraphQL::Schema::Object?} + + def execute_field_span: (Proc callable, String span_key, **executeFieldKwargs kwargs) -> Array[Object] + + def execute_field: (**executeFieldKwargs kwargs) -> Array[Object] + + def execute_field_lazy: (**executeFieldKwargs kwargs) -> Array[Object] + + type authorizedKwargs = {query: GraphQL::Query, type: GraphQL::Schema::Object, object: GraphQL::Schema::Object?} + + def authorized_span: (Proc callable, String span_key, **authorizedKwargs kwargs) -> GraphQL::Schema::Object? + + def authorized: (**authorizedKwargs kwargs) -> GraphQL::Schema::Object? + + def authorized_lazy: (**authorizedKwargs kwargs) -> GraphQL::Schema::Object? + + type resolveTypeKwargs = {query: GraphQL::Query, type: GraphQL::Schema::Union, object: GraphQL::Schema::Object?} + + def resolve_type_span: (Proc callable, String span_key, **resolveTypeKwargs kwargs) -> [GraphQL::Schema::Object, nil] + + def resolve_type: (**resolveTypeKwargs kwargs) -> [GraphQL::Schema::Object, nil] + + def resolve_type_lazy: (**resolveTypeKwargs kwargs) -> [GraphQL::Schema::Object, nil] + + def platform_field_key: (GraphQL::Schema::Field field) -> String + + def platform_authorized_key: (GraphQL::Schema::Object type) -> String + + def platform_resolve_type_key: (GraphQL::Schema::Union type) -> String + + private + + type traceKwargsValues = GraphQL::Query | GraphQL::Schema::Union | GraphQL::Schema::Object | GraphQL::Schema::Field | GraphQL::Execution::Multiplex | GraphQL::Language::Nodes::Field | Hash[Symbol, String] | String | bool | nil + + type traceResult = lexerArray | GraphQL::Language::Nodes::Document | { remaining_timeout: Float?, error: Array[StandardError] } | Array[Object] | GraphQL::Schema::Object? | [GraphQL::Schema::Object, nil] + + def trace: (Proc callable, String trace_key, String resource, **Hash[Symbol, traceKwargsValues ] kwargs) ?{ (Datadog::Tracing::SpanOperation) -> void } -> traceResult + + def multiplex_resource: (GraphQL::Execution::Multiplex multiplex) -> String? + end + end + end + end +end diff --git a/sig/datadog/tracing/contrib/graphql/unified_trace_patcher.rbs b/sig/datadog/tracing/contrib/graphql/unified_trace_patcher.rbs new file mode 100644 index 00000000000..3a79304cadd --- /dev/null +++ b/sig/datadog/tracing/contrib/graphql/unified_trace_patcher.rbs @@ -0,0 +1,11 @@ +module Datadog + module Tracing + module Contrib + module GraphQL + module UnifiedTracePatcher + def self?.patch!: (Array[GraphQL::Schema] schemas, Hash[Symbol, bool | Float | String | nil] options) -> void + end + end + end + end +end diff --git a/spec/datadog/tracing/contrib/graphql/configuration/settings_spec.rb b/spec/datadog/tracing/contrib/graphql/configuration/settings_spec.rb index 1487c1d14a0..9591c4b3c50 100644 --- a/spec/datadog/tracing/contrib/graphql/configuration/settings_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/configuration/settings_spec.rb @@ -54,4 +54,30 @@ end end end + + describe 'with_unified_tracer' do + context 'when default' do + it do + settings = described_class.new + + expect(settings.with_unified_tracer).to eq(false) + end + end + + context 'when given `true`' do + it do + settings = described_class.new(with_unified_tracer: true) + + expect(settings.with_unified_tracer).to eq(true) + end + end + + context 'when given `false`' do + it do + settings = described_class.new(with_unified_tracer: false) + + expect(settings.with_unified_tracer).to eq(false) + end + end + end end diff --git a/spec/datadog/tracing/contrib/graphql/patcher_spec.rb b/spec/datadog/tracing/contrib/graphql/patcher_spec.rb index f02618d0984..d828918fd1f 100644 --- a/spec/datadog/tracing/contrib/graphql/patcher_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/patcher_spec.rb @@ -2,6 +2,7 @@ require 'datadog/tracing/contrib/graphql/test_schema_examples' require 'datadog/tracing/contrib/graphql/tracing_patcher' require 'datadog/tracing/contrib/graphql/trace_patcher' +require 'datadog/tracing/contrib/graphql/unified_trace_patcher' require 'datadog' @@ -64,6 +65,48 @@ end end + context 'with with_unified_tracer enabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(true) + expect(Datadog::Tracing::Contrib::GraphQL::UnifiedTracePatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: true + end + end + end + + context 'with with_unified_tracer disabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(true) + expect(Datadog::Tracing::Contrib::GraphQL::TracePatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: false + end + end + end + + context 'with with_unified_tracer enabled and with_deprecated_tracer enabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(true) + expect(Datadog::Tracing::Contrib::GraphQL::TracingPatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: true, with_deprecated_tracer: true + end + end + end + context 'with given schema' do it do allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(true) @@ -127,6 +170,52 @@ end end + context 'with with_unified_tracer enabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(false) + expect(Datadog::Tracing::Contrib::GraphQL::TracingPatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + expect_any_instance_of(Datadog::Core::Logger).to receive(:warn) + .with(/Falling back to GraphQL::Tracing::DataDogTracing/) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: true + end + end + end + + context 'with with_unified_tracer disabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(false) + expect(Datadog::Tracing::Contrib::GraphQL::TracingPatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + expect_any_instance_of(Datadog::Core::Logger).to receive(:warn) + .with(/Falling back to GraphQL::Tracing::DataDogTracing/) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: false + end + end + end + + context 'with with_unified_tracer enabled and with_deprecated_tracer enabled' do + it do + allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(false) + expect(Datadog::Tracing::Contrib::GraphQL::TracingPatcher).to receive(:patch!).with( + [], + hash_including(:analytics_enabled, :analytics_sample_rate, :service) + ) + + Datadog.configure do |c| + c.tracing.instrument :graphql, with_unified_tracer: true, with_deprecated_tracer: true + end + end + end + context 'with given schema' do it do allow(Datadog::Tracing::Contrib::GraphQL::Integration).to receive(:trace_supported?).and_return(false) diff --git a/spec/datadog/tracing/contrib/graphql/test_schema_examples.rb b/spec/datadog/tracing/contrib/graphql/test_schema_examples.rb index 15e7e9f83d5..beb8f84e584 100644 --- a/spec/datadog/tracing/contrib/graphql/test_schema_examples.rb +++ b/spec/datadog/tracing/contrib/graphql/test_schema_examples.rb @@ -23,7 +23,7 @@ class TestGraphQLSchema < ::GraphQL::Schema query(TestGraphQLQuery) end -RSpec.shared_examples 'graphql instrumentation' do +RSpec.shared_examples 'graphql default instrumentation' do around do |example| Datadog::GraphQLTestHelpers.reset_schema_cache!(::GraphQL::Schema) Datadog::GraphQLTestHelpers.reset_schema_cache!(TestGraphQLSchema) @@ -69,3 +69,74 @@ class TestGraphQLSchema < ::GraphQL::Schema end end end + +RSpec.shared_examples 'graphql instrumentation with unified naming convention trace' do + around do |example| + Datadog::GraphQLTestHelpers.reset_schema_cache!(::GraphQL::Schema) + Datadog::GraphQLTestHelpers.reset_schema_cache!(TestGraphQLSchema) + + example.run + + Datadog::GraphQLTestHelpers.reset_schema_cache!(::GraphQL::Schema) + Datadog::GraphQLTestHelpers.reset_schema_cache!(TestGraphQLSchema) + end + + describe 'query trace' do + subject(:result) do + TestGraphQLSchema.execute(query: 'query Users($var: ID!){ user(id: $var) { name } }', variables: { var: 1 }) + end + + matrix = [ + ['graphql.analyze', 'query Users($var: ID!){ user(id: $var) { name } }'], + ['graphql.analyze_multiplex', 'Users'], + ['graphql.authorized', 'TestGraphQLQuery.authorized'], + ['graphql.authorized', 'TestUser.authorized'], + ['graphql.execute', 'Users'], + ['graphql.execute_lazy', 'Users'], + ['graphql.execute_multiplex', 'Users'], + if Gem::Version.new(GraphQL::VERSION) < Gem::Version.new('2.2') + ['graphql.lex', 'query Users($var: ID!){ user(id: $var) { name } }'] + end, + ['graphql.parse', 'query Users($var: ID!){ user(id: $var) { name } }'], + ['graphql.resolve', 'TestGraphQLQuery.user'], + ['graphql.resolve', 'TestUser.name'], + # New Ruby-based parser doesn't emit a "lex" event. (graphql/c_parser still does.) + ['graphql.validate', 'Users'] + ].compact + + # graphql.source for execute_multiplex is not required in the span attributes specification + spans_with_source = ['graphql.parse', 'graphql.validate', 'graphql.execute'] + + matrix.each_with_index do |(name, resource), index| + it "creates #{name} span with #{resource} resource" do + expect(result.to_h['errors']).to be nil + expect(result.to_h['data']).to eq({ 'user' => { 'name' => 'Bits' } }) + + expect(spans).to have(matrix.length).items + span = spans[index] + + expect(span.name).to eq(name) + expect(span.resource).to eq(resource) + expect(span.service).to eq(tracer.default_service) + expect(span.type).to eq('graphql') + + if spans_with_source.include?(name) + expect(span.get_tag('graphql.source')).to eq('query Users($var: ID!){ user(id: $var) { name } }') + end + + if name == 'graphql.execute' + expect(span.get_tag('graphql.operation.type')).to eq('query') + expect(span.get_tag('graphql.operation.name')).to eq('Users') + # graphql.variables.* in graphql.execute span are the ones defined outside the query + # (variables part in JSON for example) + expect(span.get_tag('graphql.variables.var')).to eq(1) + end + + if name == 'graphql.resolve' && resource == 'TestGraphQLQuery.user' + # During graphql.resolve, it converts it to string (as it builds an SQL query for example) + expect(span.get_tag('graphql.variables.id')).to eq('1') + end + end + end + end +end diff --git a/spec/datadog/tracing/contrib/graphql/trace_patcher_spec.rb b/spec/datadog/tracing/contrib/graphql/trace_patcher_spec.rb index 6e225cf8aaf..a3898903d8e 100644 --- a/spec/datadog/tracing/contrib/graphql/trace_patcher_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/trace_patcher_spec.rb @@ -8,7 +8,7 @@ skip: Gem::Version.new(::GraphQL::VERSION) < Gem::Version.new('2.0.19') do describe '#patch!' do context 'with empty schema configuration' do - it_behaves_like 'graphql instrumentation' do + it_behaves_like 'graphql default instrumentation' do before do described_class.patch!([], {}) end @@ -16,7 +16,7 @@ end context 'with specified schemas configuration' do - it_behaves_like 'graphql instrumentation' do + it_behaves_like 'graphql default instrumentation' do before do described_class.patch!([TestGraphQLSchema], {}) end diff --git a/spec/datadog/tracing/contrib/graphql/tracing_patcher_spec.rb b/spec/datadog/tracing/contrib/graphql/tracing_patcher_spec.rb index 0943e474b5f..db036f6e4ac 100644 --- a/spec/datadog/tracing/contrib/graphql/tracing_patcher_spec.rb +++ b/spec/datadog/tracing/contrib/graphql/tracing_patcher_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Datadog::Tracing::Contrib::GraphQL::TracingPatcher do describe '#patch!' do context 'with empty schema configuration' do - it_behaves_like 'graphql instrumentation' do + it_behaves_like 'graphql default instrumentation' do before do described_class.patch!([], {}) end @@ -15,7 +15,7 @@ end context 'with specified schemas configuration' do - it_behaves_like 'graphql instrumentation' do + it_behaves_like 'graphql default instrumentation' do before do described_class.patch!([TestGraphQLSchema], {}) end diff --git a/spec/datadog/tracing/contrib/graphql/unified_trace_patcher_spec.rb b/spec/datadog/tracing/contrib/graphql/unified_trace_patcher_spec.rb new file mode 100644 index 00000000000..ff94f1fbc8e --- /dev/null +++ b/spec/datadog/tracing/contrib/graphql/unified_trace_patcher_spec.rb @@ -0,0 +1,26 @@ +require 'datadog/tracing/contrib/support/spec_helper' +require 'datadog/tracing/contrib/graphql/test_schema_examples' +require 'datadog/tracing/contrib/graphql/unified_trace_patcher' + +require 'datadog' + +RSpec.describe Datadog::Tracing::Contrib::GraphQL::UnifiedTracePatcher, + skip: Gem::Version.new(::GraphQL::VERSION) < Gem::Version.new('2.0.19') do + describe '#patch!' do + context 'with empty schema configuration' do + it_behaves_like 'graphql instrumentation with unified naming convention trace' do + before do + described_class.patch!([], {}) + end + end + end + + context 'with specified schemas configuration' do + it_behaves_like 'graphql instrumentation with unified naming convention trace' do + before do + described_class.patch!([TestGraphQLSchema], {}) + end + end + end + end + end diff --git a/vendor/rbs/graphql/0/graphql.rbs b/vendor/rbs/graphql/0/graphql.rbs new file mode 100644 index 00000000000..81f931ae6c7 --- /dev/null +++ b/vendor/rbs/graphql/0/graphql.rbs @@ -0,0 +1,37 @@ +module GraphQL + class Schema + class Field + end + + class Object + end + + class Union + end + end + + module Tracing + class Trace + end + end + + module Language + module Nodes + class Document + end + + class Field + end + end + end + + class Query + class Result + end + end + + module Execution + class Multiplex + end + end +end \ No newline at end of file