graphql 2.4.13 → 2.5.11
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.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/query_complexity.rb +87 -7
- data/lib/graphql/backtrace/table.rb +37 -14
- data/lib/graphql/current.rb +1 -1
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +27 -0
- data/lib/graphql/dashboard/statics/dashboard.js +74 -9
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +49 -1
- data/lib/graphql/dashboard.rb +45 -29
- data/lib/graphql/dataloader/active_record_association_source.rb +28 -8
- data/lib/graphql/dataloader/active_record_source.rb +26 -5
- data/lib/graphql/dataloader/null_dataloader.rb +7 -0
- data/lib/graphql/dataloader/source.rb +16 -4
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +34 -1
- data/lib/graphql/execution/interpreter/runtime.rb +163 -59
- data/lib/graphql/execution/interpreter.rb +5 -13
- data/lib/graphql/execution/multiplex.rb +6 -1
- data/lib/graphql/invalid_null_error.rb +15 -2
- data/lib/graphql/language/lexer.rb +9 -2
- data/lib/graphql/language/nodes.rb +5 -1
- data/lib/graphql/language/parser.rb +14 -6
- data/lib/graphql/query/context.rb +3 -8
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query.rb +59 -55
- data/lib/graphql/schema/addition.rb +3 -1
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +9 -3
- data/lib/graphql/schema/build_from_definition.rb +96 -47
- data/lib/graphql/schema/directive/flagged.rb +2 -0
- data/lib/graphql/schema/directive.rb +33 -1
- data/lib/graphql/schema/field.rb +23 -1
- data/lib/graphql/schema/input_object.rb +38 -30
- data/lib/graphql/schema/list.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_dataloader.rb +4 -2
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_interfaces.rb +2 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -2
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/resolver.rb +1 -0
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/validator/required_validator.rb +15 -6
- data/lib/graphql/schema/visibility/migration.rb +2 -2
- data/lib/graphql/schema/visibility/profile.rb +107 -21
- data/lib/graphql/schema/visibility.rb +41 -29
- data/lib/graphql/schema/warden.rb +13 -5
- data/lib/graphql/schema.rb +228 -32
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +78 -16
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +6 -2
- data/lib/graphql/testing/helpers.rb +5 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +7 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +5 -0
- data/lib/graphql/tracing/appsignal_trace.rb +26 -61
- data/lib/graphql/tracing/data_dog_trace.rb +41 -164
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +34 -164
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/null_trace.rb +1 -1
- data/lib/graphql/tracing/perfetto_trace.rb +16 -19
- data/lib/graphql/tracing/prometheus_trace.rb +47 -74
- data/lib/graphql/tracing/scout_trace.rb +25 -59
- data/lib/graphql/tracing/sentry_trace.rb +56 -99
- data/lib/graphql/tracing/statsd_trace.rb +24 -47
- data/lib/graphql/tracing/trace.rb +0 -17
- data/lib/graphql/tracing.rb +1 -0
- data/lib/graphql/type_kinds.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -1
- metadata +35 -26
- data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +0 -63
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -0,0 +1,283 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Tracing
|
5
|
+
# This module is the basis for Ruby-level integration with third-party monitoring platforms.
|
6
|
+
# Platform-specific traces include this module and implement an adapter.
|
7
|
+
#
|
8
|
+
# @see ActiveSupportNotificationsTrace Integration via ActiveSupport::Notifications, an alternative approach.
|
9
|
+
module MonitorTrace
|
10
|
+
class Monitor
|
11
|
+
def initialize(trace:, set_transaction_name:, **_rest)
|
12
|
+
@trace = trace
|
13
|
+
@set_transaction_name = set_transaction_name
|
14
|
+
@platform_field_key_cache = Hash.new { |h, k| h[k] = platform_field_key(k) }.compare_by_identity
|
15
|
+
@platform_authorized_key_cache = Hash.new { |h, k| h[k] = platform_authorized_key(k) }.compare_by_identity
|
16
|
+
@platform_resolve_type_key_cache = Hash.new { |h, k| h[k] = platform_resolve_type_key(k) }.compare_by_identity
|
17
|
+
@platform_source_class_key_cache = Hash.new { |h, source_cls| h[source_cls] = platform_source_class_key(source_cls) }.compare_by_identity
|
18
|
+
end
|
19
|
+
|
20
|
+
def instrument(keyword, object, &block)
|
21
|
+
raise "Implement #{self.class}#instrument to measure the block"
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_event(keyword, object)
|
25
|
+
ev = self.class::Event.new(self, keyword, object)
|
26
|
+
ev.start
|
27
|
+
ev
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the transaction name based on the operation type and name if possible, or fall back to a user provided
|
31
|
+
# one. Useful for anonymous queries.
|
32
|
+
def transaction_name(query)
|
33
|
+
selected_op = query.selected_operation
|
34
|
+
txn_name = if selected_op
|
35
|
+
op_type = selected_op.operation_type
|
36
|
+
op_name = selected_op.name || fallback_transaction_name(query.context) || "anonymous"
|
37
|
+
"#{op_type}.#{op_name}"
|
38
|
+
else
|
39
|
+
"query.anonymous"
|
40
|
+
end
|
41
|
+
"GraphQL/#{txn_name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def fallback_transaction_name(context)
|
45
|
+
context[:tracing_fallback_transaction_name]
|
46
|
+
end
|
47
|
+
|
48
|
+
def name_for(keyword, object)
|
49
|
+
case keyword
|
50
|
+
when :execute_field
|
51
|
+
@platform_field_key_cache[object]
|
52
|
+
when :authorized
|
53
|
+
@platform_authorized_key_cache[object]
|
54
|
+
when :resolve_type
|
55
|
+
@platform_resolve_type_key_cache[object]
|
56
|
+
when :dataloader_source
|
57
|
+
@platform_source_class_key_cache[object.class]
|
58
|
+
when :parse then self.class::PARSE_NAME
|
59
|
+
when :lex then self.class::LEX_NAME
|
60
|
+
when :execute then self.class::EXECUTE_NAME
|
61
|
+
when :analyze then self.class::ANALYZE_NAME
|
62
|
+
when :validate then self.class::VALIDATE_NAME
|
63
|
+
else
|
64
|
+
raise "No name for #{keyword.inspect}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Event
|
69
|
+
def initialize(monitor, keyword, object)
|
70
|
+
@monitor = monitor
|
71
|
+
@keyword = keyword
|
72
|
+
@object = object
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :keyword, :object
|
76
|
+
|
77
|
+
def start
|
78
|
+
raise "Implement #{self.class}#start to begin a new event (#{inspect})"
|
79
|
+
end
|
80
|
+
|
81
|
+
def finish
|
82
|
+
raise "Implement #{self.class}#finish to end this event (#{inspect})"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module GraphQLSuffixNames
|
87
|
+
PARSE_NAME = "parse.graphql"
|
88
|
+
LEX_NAME = "lex.graphql"
|
89
|
+
VALIDATE_NAME = "validate.graphql"
|
90
|
+
EXECUTE_NAME = "execute.graphql"
|
91
|
+
ANALYZE_NAME = "analyze.graphql"
|
92
|
+
|
93
|
+
def platform_field_key(field)
|
94
|
+
"#{field.path}.graphql"
|
95
|
+
end
|
96
|
+
|
97
|
+
def platform_authorized_key(type)
|
98
|
+
"#{type.graphql_name}.authorized.graphql"
|
99
|
+
end
|
100
|
+
|
101
|
+
def platform_resolve_type_key(type)
|
102
|
+
"#{type.graphql_name}.resolve_type.graphql"
|
103
|
+
end
|
104
|
+
|
105
|
+
def platform_source_class_key(source_class)
|
106
|
+
"#{source_class.name.gsub("::", "_")}.fetch.graphql"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module GraphQLPrefixNames
|
111
|
+
PARSE_NAME = "graphql.parse"
|
112
|
+
LEX_NAME = "graphql.lex"
|
113
|
+
VALIDATE_NAME = "graphql.validate"
|
114
|
+
EXECUTE_NAME = "graphql.execute"
|
115
|
+
ANALYZE_NAME = "graphql.analyze"
|
116
|
+
|
117
|
+
def platform_field_key(field)
|
118
|
+
"graphql.#{field.path}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def platform_authorized_key(type)
|
122
|
+
"graphql.authorized.#{type.graphql_name}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def platform_resolve_type_key(type)
|
126
|
+
"graphql.resolve_type.#{type.graphql_name}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def platform_source_class_key(source_class)
|
130
|
+
"graphql.fetch.#{source_class.name.gsub("::", "_")}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.create_module(monitor_name)
|
136
|
+
if !monitor_name.match?(/[a-z]+/)
|
137
|
+
raise ArgumentError, "monitor name must be [a-z]+, not: #{monitor_name.inspect}"
|
138
|
+
end
|
139
|
+
|
140
|
+
trace_module = Module.new
|
141
|
+
code = MODULE_TEMPLATE % {
|
142
|
+
monitor: monitor_name,
|
143
|
+
monitor_class: monitor_name.capitalize + "Monitor",
|
144
|
+
}
|
145
|
+
trace_module.module_eval(code, __FILE__, __LINE__ + 5) # rubocop:disable Development/NoEvalCop This is build-time with a validated string
|
146
|
+
trace_module
|
147
|
+
end
|
148
|
+
|
149
|
+
MODULE_TEMPLATE = <<~RUBY
|
150
|
+
# @param set_transaction_name [Boolean] If `true`, use the GraphQL operation name as the request name on the monitoring platform
|
151
|
+
# @param trace_scalars [Boolean] If `true`, leaf fields will be traced too (Scalars _and_ Enums)
|
152
|
+
# @param trace_authorized [Boolean] If `false`, skip tracing `authorized?` calls
|
153
|
+
# @param trace_resolve_type [Boolean] If `false`, skip tracing `resolve_type?` calls
|
154
|
+
def initialize(...)
|
155
|
+
setup_%{monitor}_monitor(...)
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
def setup_%{monitor}_monitor(trace_scalars: false, trace_authorized: true, trace_resolve_type: true, set_transaction_name: false, **kwargs)
|
160
|
+
@trace_scalars = trace_scalars
|
161
|
+
@trace_authorized = trace_authorized
|
162
|
+
@trace_resolve_type = trace_resolve_type
|
163
|
+
@set_transaction_name = set_transaction_name
|
164
|
+
@%{monitor} = %{monitor_class}.new(trace: self, set_transaction_name: @set_transaction_name, **kwargs)
|
165
|
+
end
|
166
|
+
|
167
|
+
def parse(query_string:)
|
168
|
+
@%{monitor}.instrument(:parse, query_string) do
|
169
|
+
super
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def lex(query_string:)
|
174
|
+
@%{monitor}.instrument(:lex, query_string) do
|
175
|
+
super
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def validate(query:, validate:)
|
180
|
+
@%{monitor}.instrument(:validate, query) do
|
181
|
+
super
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def begin_analyze_multiplex(multiplex, analyzers)
|
186
|
+
begin_%{monitor}_event(:analyze, nil)
|
187
|
+
super
|
188
|
+
end
|
189
|
+
|
190
|
+
def end_analyze_multiplex(multiplex, analyzers)
|
191
|
+
finish_%{monitor}_event
|
192
|
+
super
|
193
|
+
end
|
194
|
+
|
195
|
+
def execute_multiplex(multiplex:)
|
196
|
+
@%{monitor}.instrument(:execute, multiplex) do
|
197
|
+
super
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def begin_execute_field(field, object, arguments, query)
|
202
|
+
return_type = field.type.unwrap
|
203
|
+
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
204
|
+
(field.trace.nil? && @trace_scalars) || field.trace
|
205
|
+
else
|
206
|
+
true
|
207
|
+
end
|
208
|
+
|
209
|
+
if trace_field
|
210
|
+
begin_%{monitor}_event(:execute_field, field)
|
211
|
+
end
|
212
|
+
super
|
213
|
+
end
|
214
|
+
|
215
|
+
def end_execute_field(field, object, arguments, query, result)
|
216
|
+
finish_%{monitor}_event
|
217
|
+
super
|
218
|
+
end
|
219
|
+
|
220
|
+
def dataloader_fiber_yield(source)
|
221
|
+
Fiber[PREVIOUS_EV_KEY] = finish_%{monitor}_event
|
222
|
+
super
|
223
|
+
end
|
224
|
+
|
225
|
+
def dataloader_fiber_resume(source)
|
226
|
+
prev_ev = Fiber[PREVIOUS_EV_KEY]
|
227
|
+
if prev_ev
|
228
|
+
begin_%{monitor}_event(prev_ev.keyword, prev_ev.object)
|
229
|
+
end
|
230
|
+
super
|
231
|
+
end
|
232
|
+
|
233
|
+
def begin_authorized(type, object, context)
|
234
|
+
@trace_authorized && begin_%{monitor}_event(:authorized, type)
|
235
|
+
super
|
236
|
+
end
|
237
|
+
|
238
|
+
def end_authorized(type, object, context, result)
|
239
|
+
finish_%{monitor}_event
|
240
|
+
super
|
241
|
+
end
|
242
|
+
|
243
|
+
def begin_resolve_type(type, value, context)
|
244
|
+
@trace_resolve_type && begin_%{monitor}_event(:resolve_type, type)
|
245
|
+
super
|
246
|
+
end
|
247
|
+
|
248
|
+
def end_resolve_type(type, value, context, resolved_type)
|
249
|
+
finish_%{monitor}_event
|
250
|
+
super
|
251
|
+
end
|
252
|
+
|
253
|
+
def begin_dataloader_source(source)
|
254
|
+
begin_%{monitor}_event(:dataloader_source, source)
|
255
|
+
super
|
256
|
+
end
|
257
|
+
|
258
|
+
def end_dataloader_source(source)
|
259
|
+
finish_%{monitor}_event
|
260
|
+
super
|
261
|
+
end
|
262
|
+
|
263
|
+
CURRENT_EV_KEY = :__graphql_%{monitor}_trace_event
|
264
|
+
PREVIOUS_EV_KEY = :__graphql_%{monitor}_trace_previous_event
|
265
|
+
|
266
|
+
private
|
267
|
+
|
268
|
+
def begin_%{monitor}_event(keyword, object)
|
269
|
+
Fiber[CURRENT_EV_KEY] = @%{monitor}.start_event(keyword, object)
|
270
|
+
end
|
271
|
+
|
272
|
+
def finish_%{monitor}_event
|
273
|
+
if ev = Fiber[CURRENT_EV_KEY]
|
274
|
+
ev.finish
|
275
|
+
# Use `false` to prevent grabbing an event from a parent fiber
|
276
|
+
Fiber[CURRENT_EV_KEY] = false
|
277
|
+
ev
|
278
|
+
end
|
279
|
+
end
|
280
|
+
RUBY
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "graphql/tracing/
|
3
|
+
require "graphql/tracing/monitor_trace"
|
4
4
|
|
5
5
|
module GraphQL
|
6
6
|
module Tracing
|
@@ -16,183 +16,53 @@ module GraphQL
|
|
16
16
|
#
|
17
17
|
# @example Installing without trace events for `authorized?` or `resolve_type` calls
|
18
18
|
# trace_with GraphQL::Tracing::NewRelicTrace, trace_authorized: false, trace_resolve_type: false
|
19
|
+
NewRelicTrace = MonitorTrace.create_module("newrelic")
|
19
20
|
module NewRelicTrace
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
h[type] = "GraphQL/Authorized/#{type.graphql_name}"
|
37
|
-
end.compare_by_identity
|
38
|
-
|
39
|
-
@nr_resolve_type_names = Hash.new do |h, type|
|
40
|
-
h[type] = "GraphQL/ResolveType/#{type.graphql_name}"
|
41
|
-
end.compare_by_identity
|
42
|
-
|
43
|
-
@nr_source_names = Hash.new do |h, source_inst|
|
44
|
-
h[source_inst] = "GraphQL/Source/#{source_inst.class.name}"
|
45
|
-
end.compare_by_identity
|
46
|
-
|
47
|
-
@nr_parse = @nr_validate = @nr_analyze = @nr_execute = nil
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
def begin_parse(query_str)
|
52
|
-
@nr_parse = NewRelic::Agent::Tracer.start_transaction_or_segment(partial_name: "GraphQL/parse", category: :web)
|
53
|
-
super
|
54
|
-
end
|
55
|
-
|
56
|
-
def end_parse(query_str)
|
57
|
-
@nr_parse.finish
|
58
|
-
super
|
59
|
-
end
|
60
|
-
|
61
|
-
def begin_validate(query, validate)
|
62
|
-
@nr_validate = NewRelic::Agent::Tracer.start_transaction_or_segment(partial_name: "GraphQL/validate", category: :web)
|
63
|
-
super
|
64
|
-
end
|
65
|
-
|
66
|
-
def end_validate(query, validate, validation_errors)
|
67
|
-
@nr_validate.finish
|
68
|
-
super
|
69
|
-
end
|
70
|
-
|
71
|
-
def begin_analyze_multiplex(multiplex, analyzers)
|
72
|
-
@nr_analyze = NewRelic::Agent::Tracer.start_transaction_or_segment(partial_name: "GraphQL/analyze", category: :web)
|
73
|
-
super
|
74
|
-
end
|
75
|
-
|
76
|
-
def end_analyze_multiplex(multiplex, analyzers)
|
77
|
-
@nr_analyze.finish
|
78
|
-
super
|
79
|
-
end
|
80
|
-
|
81
|
-
def begin_execute_multiplex(multiplex)
|
82
|
-
query = multiplex.queries.first
|
83
|
-
set_this_txn_name = query.context[:set_new_relic_transaction_name]
|
84
|
-
if set_this_txn_name || (set_this_txn_name.nil? && @set_transaction_name)
|
85
|
-
NewRelic::Agent.set_transaction_name(transaction_name(query))
|
86
|
-
end
|
87
|
-
@nr_execute = NewRelic::Agent::Tracer.start_transaction_or_segment(partial_name: "GraphQL/execute", category: :web)
|
88
|
-
super
|
89
|
-
end
|
90
|
-
|
91
|
-
def end_execute_multiplex(multiplex)
|
92
|
-
@nr_execute.finish
|
93
|
-
super
|
94
|
-
end
|
95
|
-
|
96
|
-
def begin_execute_field(field, object, arguments, query)
|
97
|
-
return_type = field.type.unwrap
|
98
|
-
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
99
|
-
(field.trace.nil? && @trace_scalars) || field.trace
|
100
|
-
else
|
101
|
-
true
|
21
|
+
class NewrelicMonitor < MonitorTrace::Monitor
|
22
|
+
PARSE_NAME = "GraphQL/parse"
|
23
|
+
LEX_NAME = "GraphQL/lex"
|
24
|
+
VALIDATE_NAME = "GraphQL/validate"
|
25
|
+
EXECUTE_NAME = "GraphQL/execute"
|
26
|
+
ANALYZE_NAME = "GraphQL/analyze"
|
27
|
+
|
28
|
+
def instrument(keyword, payload, &block)
|
29
|
+
if keyword == :execute
|
30
|
+
query = payload.queries.first
|
31
|
+
set_this_txn_name = query.context[:set_new_relic_transaction_name]
|
32
|
+
if set_this_txn_name || (set_this_txn_name.nil? && @set_transaction_name)
|
33
|
+
NewRelic::Agent.set_transaction_name(transaction_name(query))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(name_for(keyword, payload), &block)
|
102
37
|
end
|
103
|
-
if trace_field
|
104
|
-
start_segment(partial_name: @nr_field_names[field], category: :web)
|
105
|
-
end
|
106
|
-
super
|
107
|
-
end
|
108
|
-
|
109
|
-
def end_execute_field(field, objects, arguments, query, result)
|
110
|
-
finish_segment
|
111
|
-
super
|
112
|
-
end
|
113
38
|
|
114
|
-
|
115
|
-
|
116
|
-
start_segment(partial_name: @nr_authorized_names[type], category: :web)
|
39
|
+
def platform_source_class_key(source_class)
|
40
|
+
"GraphQL/Source/#{source_class.name}"
|
117
41
|
end
|
118
|
-
super
|
119
|
-
end
|
120
42
|
|
121
|
-
|
122
|
-
|
123
|
-
finish_segment
|
43
|
+
def platform_field_key(field)
|
44
|
+
"GraphQL/#{field.owner.graphql_name}/#{field.graphql_name}"
|
124
45
|
end
|
125
|
-
super
|
126
|
-
end
|
127
46
|
|
128
|
-
|
129
|
-
|
130
|
-
start_segment(partial_name: @nr_resolve_type_names[type], category: :web)
|
47
|
+
def platform_authorized_key(type)
|
48
|
+
"GraphQL/Authorized/#{type.graphql_name}"
|
131
49
|
end
|
132
|
-
super
|
133
|
-
end
|
134
50
|
|
135
|
-
|
136
|
-
|
137
|
-
finish_segment
|
51
|
+
def platform_resolve_type_key(type)
|
52
|
+
"GraphQL/ResolveType/#{type.graphql_name}"
|
138
53
|
end
|
139
|
-
super
|
140
|
-
end
|
141
|
-
|
142
|
-
def begin_dataloader_source(source)
|
143
|
-
start_segment(partial_name: @nr_source_names[source], category: :web)
|
144
|
-
super
|
145
|
-
end
|
146
54
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
55
|
+
class Event < MonitorTrace::Monitor::Event
|
56
|
+
def start
|
57
|
+
name = @monitor.name_for(keyword, object)
|
58
|
+
@nr_ev = NewRelic::Agent::Tracer.start_transaction_or_segment(partial_name: name, category: :web)
|
59
|
+
end
|
151
60
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
super
|
156
|
-
end
|
157
|
-
|
158
|
-
def dataloader_fiber_resume(source)
|
159
|
-
prev_segment = Fiber[:graphql_nr_previous_segment]
|
160
|
-
Fiber[:graphql_nr_previous_segment] = nil
|
161
|
-
seg_partial_name = prev_segment.name.sub(/^.*(GraphQL.*)$/, '\1')
|
162
|
-
start_segment(partial_name: seg_partial_name, category: :web)
|
163
|
-
super
|
164
|
-
end
|
165
|
-
|
166
|
-
private
|
167
|
-
|
168
|
-
def start_segment(...)
|
169
|
-
Fiber[:graphql_nr_segment] = NewRelic::Agent::Tracer.start_transaction_or_segment(...)
|
170
|
-
end
|
171
|
-
|
172
|
-
def finish_segment
|
173
|
-
segment = Fiber[:graphql_nr_segment]
|
174
|
-
if segment
|
175
|
-
segment.finish
|
176
|
-
Fiber[:graphql_nr_segment] = nil
|
177
|
-
segment
|
61
|
+
def finish
|
62
|
+
@nr_ev.finish
|
63
|
+
end
|
178
64
|
end
|
179
65
|
end
|
180
|
-
|
181
|
-
def transaction_name(query)
|
182
|
-
selected_op = query.selected_operation
|
183
|
-
txn_name = if selected_op
|
184
|
-
op_type = selected_op.operation_type
|
185
|
-
op_name = selected_op.name || fallback_transaction_name(query.context) || "anonymous"
|
186
|
-
"#{op_type}.#{op_name}"
|
187
|
-
else
|
188
|
-
"query.anonymous"
|
189
|
-
end
|
190
|
-
"GraphQL/#{txn_name}"
|
191
|
-
end
|
192
|
-
|
193
|
-
def fallback_transaction_name(context)
|
194
|
-
context[:tracing_fallback_transaction_name]
|
195
|
-
end
|
196
66
|
end
|
197
67
|
end
|
198
68
|
end
|