graphql 2.2.5 → 2.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast.rb +7 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/execution/interpreter/runtime.rb +9 -0
- data/lib/graphql/execution/interpreter.rb +90 -150
- data/lib/graphql/introspection/entry_points.rb +9 -3
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +1 -2
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +11 -1
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/pagination/array_connection.rb +3 -3
- data/lib/graphql/pagination/relation_connection.rb +3 -3
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/field.rb +31 -30
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/resolver.rb +9 -5
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema.rb +49 -7
- data/lib/graphql/static_validation/literal_validator.rb +1 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +0 -3
- data/lib/graphql/testing/helpers.rb +8 -4
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +95 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -2
- metadata +24 -23
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
data/lib/graphql/schema/field.rb
CHANGED
@@ -483,41 +483,24 @@ module GraphQL
|
|
483
483
|
metadata_complexity = 0
|
484
484
|
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
485
485
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
486
|
+
lookahead.selections.each do |next_lookahead|
|
487
|
+
# this includes `pageInfo`, `nodes` and `edges` and any custom fields
|
488
|
+
# TODO this doesn't support procs yet -- unlikely to need it.
|
489
|
+
metadata_complexity += next_lookahead.field.complexity
|
490
|
+
if next_lookahead.name != :nodes && next_lookahead.name != :edges
|
491
|
+
# subfields, eg, for pageInfo -- assumes no subselections
|
492
|
+
metadata_complexity += next_lookahead.selections.size
|
493
|
+
end
|
493
494
|
end
|
494
495
|
|
495
|
-
nodes_edges_complexity = 0
|
496
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:edges)
|
497
|
-
nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
|
498
|
-
|
499
496
|
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
500
|
-
items_complexity = child_complexity - metadata_complexity
|
501
|
-
|
502
|
-
|
497
|
+
items_complexity = child_complexity - metadata_complexity
|
498
|
+
subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
|
499
|
+
# Apply this field's own complexity
|
500
|
+
apply_own_complexity_to(subfields_complexity, query, nodes)
|
503
501
|
end
|
504
502
|
else
|
505
|
-
|
506
|
-
case defined_complexity
|
507
|
-
when Proc
|
508
|
-
arguments = query.arguments_for(nodes.first, self)
|
509
|
-
if arguments.is_a?(GraphQL::ExecutionError)
|
510
|
-
return child_complexity
|
511
|
-
elsif arguments.respond_to?(:keyword_arguments)
|
512
|
-
arguments = arguments.keyword_arguments
|
513
|
-
end
|
514
|
-
|
515
|
-
defined_complexity.call(query.context, arguments, child_complexity)
|
516
|
-
when Numeric
|
517
|
-
defined_complexity + child_complexity
|
518
|
-
else
|
519
|
-
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
520
|
-
end
|
503
|
+
apply_own_complexity_to(child_complexity, query, nodes)
|
521
504
|
end
|
522
505
|
end
|
523
506
|
|
@@ -882,6 +865,24 @@ ERR
|
|
882
865
|
yield(obj, args)
|
883
866
|
end
|
884
867
|
end
|
868
|
+
|
869
|
+
def apply_own_complexity_to(child_complexity, query, nodes)
|
870
|
+
case (own_complexity = complexity)
|
871
|
+
when Numeric
|
872
|
+
own_complexity + child_complexity
|
873
|
+
when Proc
|
874
|
+
arguments = query.arguments_for(nodes.first, self)
|
875
|
+
if arguments.is_a?(GraphQL::ExecutionError)
|
876
|
+
return child_complexity
|
877
|
+
elsif arguments.respond_to?(:keyword_arguments)
|
878
|
+
arguments = arguments.keyword_arguments
|
879
|
+
end
|
880
|
+
|
881
|
+
own_complexity.call(query.context, arguments, child_complexity)
|
882
|
+
else
|
883
|
+
raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
|
884
|
+
end
|
885
|
+
end
|
885
886
|
end
|
886
887
|
end
|
887
888
|
end
|
@@ -69,7 +69,11 @@ module GraphQL
|
|
69
69
|
end
|
70
70
|
elsif child_class < GraphQL::Schema::Object
|
71
71
|
# This is being included into an object type, make sure it's using `implements(...)`
|
72
|
-
backtrace_line =
|
72
|
+
backtrace_line = caller_locations(0, 10).find do |location|
|
73
|
+
location.base_label == "implements" &&
|
74
|
+
location.path.end_with?("schema/member/has_interfaces.rb")
|
75
|
+
end
|
76
|
+
|
73
77
|
if !backtrace_line
|
74
78
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
75
79
|
end
|
@@ -166,11 +166,15 @@ module GraphQL
|
|
166
166
|
args.each_value do |argument|
|
167
167
|
arg_keyword = argument.keyword
|
168
168
|
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
169
|
-
|
170
|
-
if
|
171
|
-
return
|
172
|
-
|
173
|
-
|
169
|
+
auth_result = argument.authorized?(self, arg_value, context)
|
170
|
+
if auth_result.is_a?(Array)
|
171
|
+
# only return this second value if the application returned a second value
|
172
|
+
arg_auth, err = auth_result
|
173
|
+
if !arg_auth
|
174
|
+
return arg_auth, err
|
175
|
+
end
|
176
|
+
elsif auth_result == false
|
177
|
+
return auth_result
|
174
178
|
end
|
175
179
|
else
|
176
180
|
true
|
data/lib/graphql/schema.rb
CHANGED
@@ -225,6 +225,10 @@ module GraphQL
|
|
225
225
|
if base_class < DefaultTraceClass
|
226
226
|
mods = trace_modules_for(:default) + mods
|
227
227
|
end
|
228
|
+
# Copy the existing default options into this mode's options
|
229
|
+
default_options = trace_options_for(:default)
|
230
|
+
add_trace_options_for(mode, default_options)
|
231
|
+
|
228
232
|
Class.new(base_class) do
|
229
233
|
mods.any? && include(*mods)
|
230
234
|
end
|
@@ -743,6 +747,7 @@ module GraphQL
|
|
743
747
|
|
744
748
|
def error_bubbling(new_error_bubbling = nil)
|
745
749
|
if !new_error_bubbling.nil?
|
750
|
+
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
746
751
|
@error_bubbling = new_error_bubbling
|
747
752
|
else
|
748
753
|
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
@@ -814,6 +819,26 @@ module GraphQL
|
|
814
819
|
end
|
815
820
|
end
|
816
821
|
|
822
|
+
# @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
|
823
|
+
# @return [Array<Module>] Type definitions added to this schema
|
824
|
+
def extra_types(*new_extra_types)
|
825
|
+
if new_extra_types.any?
|
826
|
+
new_extra_types = new_extra_types.flatten
|
827
|
+
@own_extra_types ||= []
|
828
|
+
@own_extra_types.concat(new_extra_types)
|
829
|
+
end
|
830
|
+
inherited_et = find_inherited_value(:extra_types, nil)
|
831
|
+
if inherited_et
|
832
|
+
if @own_extra_types
|
833
|
+
inherited_et + @own_extra_types
|
834
|
+
else
|
835
|
+
inherited_et
|
836
|
+
end
|
837
|
+
else
|
838
|
+
@own_extra_types || EMPTY_ARRAY
|
839
|
+
end
|
840
|
+
end
|
841
|
+
|
817
842
|
def orphan_types(*new_orphan_types)
|
818
843
|
if new_orphan_types.any?
|
819
844
|
new_orphan_types = new_orphan_types.flatten
|
@@ -1044,6 +1069,12 @@ module GraphQL
|
|
1044
1069
|
end
|
1045
1070
|
|
1046
1071
|
def instrument(instrument_step, instrumenter, options = {})
|
1072
|
+
warn <<~WARN
|
1073
|
+
Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
|
1074
|
+
(From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
|
1075
|
+
|
1076
|
+
WARN
|
1077
|
+
trace_with(Tracing::LegacyHooksTrace)
|
1047
1078
|
own_instrumenters[instrument_step] << instrumenter
|
1048
1079
|
end
|
1049
1080
|
|
@@ -1106,20 +1137,23 @@ module GraphQL
|
|
1106
1137
|
tc = own_trace_modes[mode] ||= build_trace_mode(mode)
|
1107
1138
|
tc.include(trace_mod)
|
1108
1139
|
own_trace_modules[mode] << trace_mod
|
1109
|
-
|
1140
|
+
add_trace_options_for(mode, options)
|
1110
1141
|
if mode == :default
|
1111
1142
|
# This module is being added as a default tracer. If any other mode classes
|
1112
1143
|
# have already been created, but get their default behavior from a superclass,
|
1113
1144
|
# Then mix this into this schema's subclass.
|
1114
1145
|
# (But don't mix it into mode classes that aren't default-based.)
|
1115
1146
|
own_trace_modes.each do |other_mode_name, other_mode_class|
|
1116
|
-
if other_mode_class < DefaultTraceClass
|
1117
|
-
|
1147
|
+
if other_mode_class < DefaultTraceClass
|
1148
|
+
# Don't add it back to the inheritance tree if it's already there
|
1149
|
+
if !(other_mode_class < trace_mod)
|
1150
|
+
other_mode_class.include(trace_mod)
|
1151
|
+
end
|
1152
|
+
# Add any options so they'll be available
|
1153
|
+
add_trace_options_for(other_mode_name, options)
|
1118
1154
|
end
|
1119
1155
|
end
|
1120
1156
|
end
|
1121
|
-
t_opts = trace_options_for(mode)
|
1122
|
-
t_opts.merge!(options)
|
1123
1157
|
end
|
1124
1158
|
nil
|
1125
1159
|
end
|
@@ -1155,13 +1189,15 @@ module GraphQL
|
|
1155
1189
|
raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
|
1156
1190
|
else
|
1157
1191
|
own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
|
1192
|
+
options_trace_mode = :default
|
1158
1193
|
:default_backtrace
|
1159
1194
|
end
|
1160
1195
|
else
|
1161
1196
|
default_trace_mode
|
1162
1197
|
end
|
1163
1198
|
|
1164
|
-
|
1199
|
+
options_trace_mode ||= trace_mode
|
1200
|
+
base_trace_options = trace_options_for(options_trace_mode)
|
1165
1201
|
trace_options = base_trace_options.merge(options)
|
1166
1202
|
trace_class_for_mode = trace_class_for(trace_mode) || raise(ArgumentError, "#{self} has no trace class for mode: #{trace_mode.inspect}")
|
1167
1203
|
trace_class_for_mode.new(**trace_options)
|
@@ -1317,6 +1353,12 @@ module GraphQL
|
|
1317
1353
|
|
1318
1354
|
private
|
1319
1355
|
|
1356
|
+
def add_trace_options_for(mode, new_options)
|
1357
|
+
t_opts = trace_options_for(mode)
|
1358
|
+
t_opts.merge!(new_options)
|
1359
|
+
nil
|
1360
|
+
end
|
1361
|
+
|
1320
1362
|
# @param t [Module, Array<Module>]
|
1321
1363
|
# @return [void]
|
1322
1364
|
def add_type_and_traverse(t, root:)
|
@@ -1378,7 +1420,7 @@ module GraphQL
|
|
1378
1420
|
else
|
1379
1421
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1380
1422
|
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1381
|
-
@lazy_methods.set(GraphQL::Dataloader::Request, :
|
1423
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
|
1382
1424
|
end
|
1383
1425
|
end
|
1384
1426
|
@lazy_methods
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
# TODO - would be nice to use these to create an error message so the caller knows
|
111
111
|
# that required fields are missing
|
112
112
|
required_field_names = @warden.arguments(type)
|
113
|
-
.select { |argument| argument.type.kind.non_null? &&
|
113
|
+
.select { |argument| argument.type.kind.non_null? && !argument.default_value? }
|
114
114
|
.map!(&:name)
|
115
115
|
|
116
116
|
present_field_names = ast_node.arguments.map(&:name)
|
@@ -122,7 +122,6 @@ module GraphQL
|
|
122
122
|
arg_type = @warden.get_argument(type, name).type
|
123
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
124
124
|
end
|
125
|
-
|
126
125
|
if type.one_of? && ast_node.arguments.size != 1
|
127
126
|
results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
|
128
127
|
end
|
@@ -35,7 +35,7 @@ module GraphQL
|
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
36
36
|
|
37
37
|
required_fields = context.warden.arguments(parent_type)
|
38
|
-
.select{|arg| arg.type.kind.non_null?}
|
38
|
+
.select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
|
39
39
|
.map!(&:graphql_name)
|
40
40
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
@@ -28,6 +28,7 @@ module GraphQL
|
|
28
28
|
# @return [Array<Hash>]
|
29
29
|
def validate(query, validate: true, timeout: nil, max_errors: nil)
|
30
30
|
query.current_trace.validate(validate: validate, query: query) do
|
31
|
+
begin_t = Time.now
|
31
32
|
errors = if validate == false
|
32
33
|
[]
|
33
34
|
else
|
@@ -52,11 +53,13 @@ module GraphQL
|
|
52
53
|
end
|
53
54
|
|
54
55
|
{
|
56
|
+
remaining_timeout: timeout ? (timeout - (Time.now - begin_t)) : nil,
|
55
57
|
errors: errors,
|
56
58
|
}
|
57
59
|
end
|
58
60
|
rescue GraphQL::ExecutionError => e
|
59
61
|
{
|
62
|
+
remaining_timeout: nil,
|
60
63
|
errors: [e],
|
61
64
|
}
|
62
65
|
end
|
@@ -148,6 +148,8 @@ module GraphQL
|
|
148
148
|
{ TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
149
149
|
elsif obj.is_a?(OpenStruct)
|
150
150
|
{ OPEN_STRUCT_KEY => dump_value(obj.to_h) }
|
151
|
+
elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
|
152
|
+
dump_value(obj.to_a)
|
151
153
|
else
|
152
154
|
obj
|
153
155
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
require "securerandom"
|
3
3
|
require "graphql/subscriptions/broadcast_analyzer"
|
4
4
|
require "graphql/subscriptions/event"
|
5
|
-
require "graphql/subscriptions/instrumentation"
|
6
5
|
require "graphql/subscriptions/serialize"
|
7
6
|
require "graphql/subscriptions/action_cable_subscriptions"
|
8
7
|
require "graphql/subscriptions/default_subscription_resolve_extension"
|
@@ -30,8 +29,6 @@ module GraphQL
|
|
30
29
|
raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
|
31
30
|
end
|
32
31
|
|
33
|
-
instrumentation = Subscriptions::Instrumentation.new(schema: schema)
|
34
|
-
defn.instrument(:query, instrumentation)
|
35
32
|
options[:schema] = schema
|
36
33
|
schema.subscriptions = self.new(**options)
|
37
34
|
schema.add_subscription_extension_if_necessary
|
@@ -5,10 +5,7 @@ module GraphQL
|
|
5
5
|
# @param schema_class [Class<GraphQL::Schema>]
|
6
6
|
# @return [Module] A helpers module which always uses the given schema
|
7
7
|
def self.for(schema_class)
|
8
|
-
|
9
|
-
include SchemaHelpers
|
10
|
-
@@schema_class_for_helpers = schema_class
|
11
|
-
end
|
8
|
+
SchemaHelpers.for(schema_class)
|
12
9
|
end
|
13
10
|
|
14
11
|
class Error < GraphQL::Error
|
@@ -119,6 +116,13 @@ module GraphQL
|
|
119
116
|
# schema will be added later
|
120
117
|
super(nil, *args, **kwargs, &block)
|
121
118
|
end
|
119
|
+
|
120
|
+
def self.for(schema_class)
|
121
|
+
Module.new do
|
122
|
+
include SchemaHelpers
|
123
|
+
@@schema_class_for_helpers = schema_class
|
124
|
+
end
|
125
|
+
end
|
122
126
|
end
|
123
127
|
end
|
124
128
|
end
|
@@ -3,20 +3,18 @@
|
|
3
3
|
module GraphQL
|
4
4
|
module Tracing
|
5
5
|
module DataDogTrace
|
6
|
+
# @param tracer [#trace] Deprecated
|
6
7
|
# @param analytics_enabled [Boolean] Deprecated
|
7
8
|
# @param analytics_sample_rate [Float] Deprecated
|
8
|
-
def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service:
|
9
|
+
def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **rest)
|
9
10
|
if tracer.nil?
|
10
11
|
tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
11
12
|
end
|
12
13
|
@tracer = tracer
|
13
14
|
|
14
|
-
|
15
|
-
&& Datadog::Contrib::Analytics.respond_to?(:enabled?) \
|
16
|
-
&& Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
|
17
|
-
|
18
|
-
@analytics_enabled = analytics_available && Datadog::Contrib::Analytics.enabled?(analytics_enabled)
|
15
|
+
@analytics_enabled = analytics_enabled
|
19
16
|
@analytics_sample_rate = analytics_sample_rate
|
17
|
+
|
20
18
|
@service_name = service
|
21
19
|
@has_prepare_span = respond_to?(:prepare_span)
|
22
20
|
super
|
@@ -34,12 +32,9 @@ module GraphQL
|
|
34
32
|
}.each do |trace_method, trace_key|
|
35
33
|
module_eval <<-RUBY, __FILE__, __LINE__
|
36
34
|
def #{trace_method}(**data)
|
37
|
-
@tracer.trace("#{trace_key}", service: @service_name) do |span|
|
38
|
-
|
39
|
-
|
40
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
41
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, '#{trace_method}')
|
42
|
-
end
|
35
|
+
@tracer.trace("#{trace_key}", service: @service_name, type: 'custom') do |span|
|
36
|
+
span.set_tag('component', 'graphql')
|
37
|
+
span.set_tag('operation', '#{trace_method}')
|
43
38
|
|
44
39
|
#{
|
45
40
|
if trace_method == 'execute_multiplex'
|
@@ -54,10 +49,8 @@ module GraphQL
|
|
54
49
|
end
|
55
50
|
span.resource = resource if resource
|
56
51
|
|
57
|
-
#
|
58
|
-
if @analytics_enabled
|
59
|
-
Datadog::Contrib::Analytics.set_sample_rate(span, @analytics_sample_rate)
|
60
|
-
end
|
52
|
+
# [Deprecated] will be removed in the future
|
53
|
+
span.set_metric('_dd1.sr.eausr', @analytics_sample_rate) if @analytics_enabled
|
61
54
|
RUBY
|
62
55
|
elsif trace_method == 'execute_query'
|
63
56
|
<<-RUBY
|
@@ -89,12 +82,10 @@ module GraphQL
|
|
89
82
|
nil
|
90
83
|
end
|
91
84
|
if platform_key && trace_field
|
92
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
93
|
-
span.
|
94
|
-
|
95
|
-
|
96
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
97
|
-
end
|
85
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
86
|
+
span.set_tag('component', 'graphql')
|
87
|
+
span.set_tag('operation', span_key)
|
88
|
+
|
98
89
|
if @has_prepare_span
|
99
90
|
prepare_span_data = { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }
|
100
91
|
prepare_span(span_key, prepare_span_data, span)
|
@@ -125,12 +116,10 @@ module GraphQL
|
|
125
116
|
|
126
117
|
def authorized_span(span_key, object, type, query)
|
127
118
|
platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
|
128
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
129
|
-
span.
|
130
|
-
|
131
|
-
|
132
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
133
|
-
end
|
119
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
120
|
+
span.set_tag('component', 'graphql')
|
121
|
+
span.set_tag('operation', span_key)
|
122
|
+
|
134
123
|
if @has_prepare_span
|
135
124
|
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
136
125
|
end
|
@@ -158,12 +147,10 @@ module GraphQL
|
|
158
147
|
|
159
148
|
def resolve_type_span(span_key, object, type, query)
|
160
149
|
platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
|
161
|
-
@tracer.trace(platform_key, service: @service_name) do |span|
|
162
|
-
span.
|
163
|
-
|
164
|
-
|
165
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
|
166
|
-
end
|
150
|
+
@tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
|
151
|
+
span.set_tag('component', 'graphql')
|
152
|
+
span.set_tag('operation', span_key)
|
153
|
+
|
167
154
|
if @has_prepare_span
|
168
155
|
prepare_span(span_key, {object: object, type: type, query: query}, span)
|
169
156
|
end
|
@@ -15,12 +15,9 @@ module GraphQL
|
|
15
15
|
}
|
16
16
|
|
17
17
|
def platform_trace(platform_key, key, data)
|
18
|
-
tracer.trace(platform_key, service:
|
19
|
-
span.
|
20
|
-
|
21
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
|
22
|
-
span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, key)
|
23
|
-
end
|
18
|
+
tracer.trace(platform_key, service: options[:service], type: 'custom') do |span|
|
19
|
+
span.set_tag('component', 'graphql')
|
20
|
+
span.set_tag('operation', key)
|
24
21
|
|
25
22
|
if key == 'execute_multiplex'
|
26
23
|
operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
|
@@ -33,10 +30,8 @@ module GraphQL
|
|
33
30
|
end
|
34
31
|
span.resource = resource if resource
|
35
32
|
|
36
|
-
#
|
37
|
-
if analytics_enabled?
|
38
|
-
Datadog::Contrib::Analytics.set_sample_rate(span, analytics_sample_rate)
|
39
|
-
end
|
33
|
+
# [Deprecated] will be removed in the future
|
34
|
+
span.set_metric('_dd1.sr.eausr', analytics_sample_rate) if analytics_enabled?
|
40
35
|
end
|
41
36
|
|
42
37
|
if key == 'execute_query'
|
@@ -51,10 +46,6 @@ module GraphQL
|
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
54
|
-
def service_name
|
55
|
-
options.fetch(:service, 'ruby-graphql')
|
56
|
-
end
|
57
|
-
|
58
49
|
# Implement this method in a subclass to apply custom tags to datadog spans
|
59
50
|
# @param key [String] The event being traced
|
60
51
|
# @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
|
@@ -65,18 +56,13 @@ module GraphQL
|
|
65
56
|
def tracer
|
66
57
|
default_tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
|
67
58
|
|
59
|
+
# [Deprecated] options[:tracer] will be removed in the future
|
68
60
|
options.fetch(:tracer, default_tracer)
|
69
61
|
end
|
70
62
|
|
71
|
-
def analytics_available?
|
72
|
-
defined?(Datadog::Contrib::Analytics) \
|
73
|
-
&& Datadog::Contrib::Analytics.respond_to?(:enabled?) \
|
74
|
-
&& Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
|
75
|
-
end
|
76
|
-
|
77
63
|
def analytics_enabled?
|
78
64
|
# [Deprecated] options[:analytics_enabled] will be removed in the future
|
79
|
-
|
65
|
+
options.fetch(:analytics_enabled, false)
|
80
66
|
end
|
81
67
|
|
82
68
|
def analytics_sample_rate
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Tracing
|
4
|
+
module LegacyHooksTrace
|
5
|
+
def execute_multiplex(multiplex:)
|
6
|
+
multiplex_instrumenters = multiplex.schema.instrumenters[:multiplex]
|
7
|
+
query_instrumenters = multiplex.schema.instrumenters[:query]
|
8
|
+
# First, run multiplex instrumentation, then query instrumentation for each query
|
9
|
+
RunHooks.call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
|
10
|
+
RunHooks.each_query_call_hooks(query_instrumenters, multiplex.queries) do
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module RunHooks
|
17
|
+
module_function
|
18
|
+
# Call the before_ hooks of each query,
|
19
|
+
# Then yield if no errors.
|
20
|
+
# `call_hooks` takes care of appropriate cleanup.
|
21
|
+
def each_query_call_hooks(instrumenters, queries, i = 0)
|
22
|
+
if i >= queries.length
|
23
|
+
yield
|
24
|
+
else
|
25
|
+
query = queries[i]
|
26
|
+
call_hooks(instrumenters, query, :before_query, :after_query) {
|
27
|
+
each_query_call_hooks(instrumenters, queries, i + 1) {
|
28
|
+
yield
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Call each before hook, and if they all succeed, yield.
|
35
|
+
# If they don't all succeed, call after_ for each one that succeeded.
|
36
|
+
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
37
|
+
begin
|
38
|
+
successful = []
|
39
|
+
instrumenters.each do |instrumenter|
|
40
|
+
instrumenter.public_send(before_hook_name, object)
|
41
|
+
successful << instrumenter
|
42
|
+
end
|
43
|
+
|
44
|
+
# if any before hooks raise an exception, quit calling before hooks,
|
45
|
+
# but call the after hooks on anything that succeeded but also
|
46
|
+
# raise the exception that came from the before hook.
|
47
|
+
rescue GraphQL::ExecutionError => err
|
48
|
+
object.context.errors << err
|
49
|
+
rescue => e
|
50
|
+
raise call_after_hooks(successful, object, after_hook_name, e)
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
yield # Call the user code
|
55
|
+
ensure
|
56
|
+
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
57
|
+
raise ex if ex
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
62
|
+
instrumenters.reverse_each do |instrumenter|
|
63
|
+
begin
|
64
|
+
instrumenter.public_send(after_hook_name, object)
|
65
|
+
rescue => e
|
66
|
+
ex = e
|
67
|
+
end
|
68
|
+
end
|
69
|
+
ex
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -81,8 +81,10 @@ module GraphQL
|
|
81
81
|
trace_name = tracing_name.sub("Tracing", "Trace")
|
82
82
|
if GraphQL::Tracing.const_defined?(trace_name, false)
|
83
83
|
trace_module = GraphQL::Tracing.const_get(trace_name)
|
84
|
+
warn("`use(#{self.name})` is deprecated, use the equivalent `trace_with(#{trace_module.name})` instead. More info: https://graphql-ruby.org/queries/tracing.html")
|
84
85
|
schema_defn.trace_with(trace_module, **options)
|
85
86
|
else
|
87
|
+
warn("`use(#{self.name})` and `Tracing::PlatformTracing` are deprecated. Use a `trace_with(...)` module instead. More info: https://graphql-ruby.org/queries/tracing.html. Please open an issue on the GraphQL-Ruby repo if you want to discuss further!")
|
86
88
|
tracer = self.new(**options)
|
87
89
|
schema_defn.tracer(tracer)
|
88
90
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module GraphQL
|
4
4
|
module Tracing
|
5
|
-
|
5
|
+
module PrometheusTrace
|
6
6
|
class GraphQLCollector < ::PrometheusExporter::Server::TypeCollector
|
7
7
|
def initialize
|
8
8
|
@graphql_gauge = PrometheusExporter::Metric::Base.default_aggregation.new(
|
@@ -28,5 +28,7 @@ module GraphQL
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
+
# Backwards-compat:
|
32
|
+
PrometheusTracing::GraphQLCollector = PrometheusTrace::GraphQLCollector
|
31
33
|
end
|
32
34
|
end
|