graphql-metrics 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,29 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Butcher
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-20 00:00:00.000000000 Z
11
+ date: 2020-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: graphql
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.9.15
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.9.15
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - "~>"
18
46
  - !ruby/object:Gem::Version
19
- version: '1.16'
47
+ version: 2.0.2
20
48
  type: :development
21
49
  prerelease: false
22
50
  version_requirements: !ruby/object:Gem::Requirement
23
51
  requirements:
24
52
  - - "~>"
25
53
  - !ruby/object:Gem::Version
26
- version: '1.16'
54
+ version: 2.0.2
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -67,35 +95,35 @@ dependencies:
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
- name: graphql
98
+ name: activesupport
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: 1.8.2
103
+ version: 5.1.5
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
- version: 1.8.2
110
+ version: 5.1.5
83
111
  - !ruby/object:Gem::Dependency
84
- name: activesupport
112
+ name: pry
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
- - - "~>"
115
+ - - ">="
88
116
  - !ruby/object:Gem::Version
89
- version: 5.1.5
117
+ version: '0'
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
- - - "~>"
122
+ - - ">="
95
123
  - !ruby/object:Gem::Version
96
- version: 5.1.5
124
+ version: '0'
97
125
  - !ruby/object:Gem::Dependency
98
- name: pry
126
+ name: pry-byebug
99
127
  requirement: !ruby/object:Gem::Requirement
100
128
  requirements:
101
129
  - - ">="
@@ -109,7 +137,7 @@ dependencies:
109
137
  - !ruby/object:Gem::Version
110
138
  version: '0'
111
139
  - !ruby/object:Gem::Dependency
112
- name: pry-byebug
140
+ name: mocha
113
141
  requirement: !ruby/object:Gem::Requirement
114
142
  requirements:
115
143
  - - ">="
@@ -123,7 +151,7 @@ dependencies:
123
151
  - !ruby/object:Gem::Version
124
152
  version: '0'
125
153
  - !ruby/object:Gem::Dependency
126
- name: mocha
154
+ name: diffy
127
155
  requirement: !ruby/object:Gem::Requirement
128
156
  requirements:
129
157
  - - ">="
@@ -137,7 +165,7 @@ dependencies:
137
165
  - !ruby/object:Gem::Version
138
166
  version: '0'
139
167
  - !ruby/object:Gem::Dependency
140
- name: diffy
168
+ name: hashdiff
141
169
  requirement: !ruby/object:Gem::Requirement
142
170
  requirements:
143
171
  - - ">="
@@ -187,8 +215,12 @@ executables: []
187
215
  extensions: []
188
216
  extra_rdoc_files: []
189
217
  files:
218
+ - ".github/workflows/ruby.yml"
190
219
  - ".gitignore"
191
- - ".travis.yml"
220
+ - ".rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml"
221
+ - ".rubocop.yml"
222
+ - ".ruby-version"
223
+ - CHANGELOG.md
192
224
  - CODE_OF_CONDUCT.md
193
225
  - Gemfile
194
226
  - Gemfile.lock
@@ -198,11 +230,11 @@ files:
198
230
  - bin/console
199
231
  - bin/setup
200
232
  - graphql_metrics.gemspec
201
- - lib/graphql_metrics.rb
202
- - lib/graphql_metrics/extractor.rb
203
- - lib/graphql_metrics/instrumentation.rb
204
- - lib/graphql_metrics/timed_batch_executor.rb
205
- - lib/graphql_metrics/version.rb
233
+ - lib/graphql/metrics.rb
234
+ - lib/graphql/metrics/analyzer.rb
235
+ - lib/graphql/metrics/instrumentation.rb
236
+ - lib/graphql/metrics/tracer.rb
237
+ - lib/graphql/metrics/version.rb
206
238
  homepage: https://github.com/Shopify/graphql-metrics
207
239
  licenses:
208
240
  - MIT
@@ -222,8 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
254
  - !ruby/object:Gem::Version
223
255
  version: '0'
224
256
  requirements: []
225
- rubyforge_project:
226
- rubygems_version: 2.5.2.3
257
+ rubygems_version: 3.0.3
227
258
  signing_key:
228
259
  specification_version: 4
229
260
  summary: GraphQL Metrics Extractor
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.4.2
5
- before_install: gem install bundler -v 1.16.1
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "graphql_metrics/version"
4
- require "graphql_metrics/instrumentation"
5
- require "graphql_metrics/extractor"
6
- require "graphql_metrics/timed_batch_executor"
@@ -1,277 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQLMetrics
4
- class Extractor
5
- class DummyInstrumentor
6
- def after_query_start_and_end_time
7
- [nil, nil]
8
- end
9
-
10
- def after_query_resolver_times(_ast_node)
11
- []
12
- end
13
-
14
- def ctx_namespace
15
- {}
16
- end
17
- end
18
-
19
- EXPLICIT_NULL = 'EXPLICIT_NULL'
20
- IMPLICIT_NULL = 'IMPLICIT_NULL'
21
- NON_NULL = 'NON_NULL'
22
-
23
- attr_reader :query
24
-
25
- def initialize(instrumentor = DummyInstrumentor.new)
26
- @instrumentor = instrumentor
27
- end
28
-
29
- def instrumentor
30
- @instrumentor ||= DummyInstrumentor.new
31
- end
32
-
33
- def extract!(query)
34
- @query = query
35
-
36
- return unless query.valid?
37
- return unless query.irep_selection
38
-
39
- extract_query
40
-
41
- used_variables = extract_used_variables
42
-
43
- query.operations.each_value do |operation|
44
- extract_variables(operation, used_variables)
45
- end
46
-
47
- extract_node(query.irep_selection)
48
- extract_batch_loaders
49
- end
50
-
51
- def extractor_defines_any_visitors?
52
- [self, instrumentor].any? do |extractor_definer|
53
- extractor_definer.respond_to?(:query_extracted) ||
54
- extractor_definer.respond_to?(:field_extracted) ||
55
- extractor_definer.respond_to?(:argument_extracted) ||
56
- extractor_definer.respond_to?(:variable_extracted) ||
57
- extractor_definer.respond_to?(:batch_loaded_field_extracted) ||
58
- extractor_definer.respond_to?(:before_query_extracted)
59
- end
60
- end
61
-
62
- def handle_extraction_exception(ex)
63
- raise ex
64
- end
65
-
66
- private
67
-
68
- def extract_batch_loaders
69
- return unless batch_loaded_field_extracted_method = extraction_method(:batch_loaded_field_extracted)
70
-
71
- TimedBatchExecutor.timings.each do |key, resolve_meta|
72
- key, identifiers = TimedBatchExecutor.serialize_loader_key(key)
73
-
74
- batch_loaded_field_extracted_method.call(
75
- {
76
- key: key,
77
- identifiers: identifiers,
78
- times: resolve_meta[:times],
79
- perform_queue_sizes: resolve_meta[:perform_queue_sizes],
80
- },
81
- {
82
- query: query,
83
- }
84
- )
85
- end
86
- rescue StandardError => ex
87
- handle_extraction_exception(ex)
88
- ensure
89
- TimedBatchExecutor.clear_timings
90
- end
91
-
92
- def extract_query
93
- return unless query_extracted_method = extraction_method(:query_extracted)
94
-
95
- start_time, end_time = instrumentor.after_query_start_and_end_time
96
- duration = start_time && end_time ? end_time - start_time : nil
97
-
98
- query_extracted_method.call(
99
- {
100
- query_string: query.document.to_query_string,
101
- operation_type: query.selected_operation.operation_type,
102
- operation_name: query.selected_operation_name,
103
- duration: duration
104
- },
105
- {
106
- query: query,
107
- start_time: start_time,
108
- end_time: end_time
109
- }
110
- )
111
- rescue StandardError => ex
112
- handle_extraction_exception(ex)
113
- end
114
-
115
- def extract_field(irep_node)
116
- return unless field_extracted_method = extraction_method(:field_extracted)
117
- return unless irep_node.definition
118
-
119
- resolver_times = instrumentor.after_query_resolver_times(irep_node.ast_node)
120
-
121
- field_extracted_method.call(
122
- {
123
- type_name: irep_node.owner_type.name,
124
- field_name: irep_node.definition.name,
125
- deprecated: irep_node.definition.deprecation_reason.present?,
126
- resolver_times: resolver_times || [],
127
- },
128
- {
129
- irep_node: irep_node,
130
- query: query,
131
- ctx_namespace: instrumentor.ctx_namespace
132
- }
133
- )
134
-
135
- rescue StandardError => ex
136
- handle_extraction_exception(ex)
137
- end
138
-
139
- def extract_argument(value, irep_node, types)
140
- return unless argument_extracted_method = extraction_method(:argument_extracted)
141
-
142
- argument_extracted_method.call(
143
- {
144
- name: value.definition.expose_as,
145
- type: value.definition.type.unwrap.to_s,
146
- value_is_null: value.value.nil?,
147
- default_used: value.default_used?,
148
- parent_input_type: types.map(&:unwrap).last&.to_s,
149
- field_name: irep_node.definition.name,
150
- field_base_type: irep_node&.owner_type.to_s
151
- },
152
- {
153
- query: query,
154
- irep_node: irep_node,
155
- value: value,
156
- }
157
- )
158
- rescue StandardError => ex
159
- handle_extraction_exception(ex)
160
- end
161
-
162
- def extract_variables(operation, used_variables)
163
- return unless variable_extracted_method = extraction_method(:variable_extracted)
164
-
165
- operation.variables.each do |variable|
166
- value_provided = query.provided_variables.key?(variable.name)
167
-
168
- default_value_type = case variable.default_value
169
- when GraphQL::Language::Nodes::NullValue
170
- EXPLICIT_NULL
171
- when nil
172
- IMPLICIT_NULL
173
- else
174
- NON_NULL
175
- end
176
-
177
- default_used = !value_provided && default_value_type != IMPLICIT_NULL
178
-
179
- variable_extracted_method.call(
180
- {
181
- operation_name: operation.name,
182
- unwrapped_type_name: unwrapped_type(variable.type),
183
- type: variable.type.to_query_string,
184
- default_value_type: default_value_type,
185
- provided_value: value_provided,
186
- default_used: default_used,
187
- used_in_operation: used_variables.include?(variable.name)
188
- },
189
- {
190
- query: query
191
- }
192
- )
193
- end
194
- rescue StandardError => ex
195
- handle_extraction_exception(ex)
196
- end
197
-
198
- def extract_used_variables
199
- query.irep_selection.ast_node.variables.each_with_object(Set.new) { |v, set| set << v.name }
200
- end
201
-
202
- def extract_arguments(irep_node)
203
- return unless irep_node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
204
-
205
- traverse_arguments(irep_node.arguments.argument_values.values, irep_node)
206
- rescue GraphQL::ExecutionError
207
- # no-op. See https://github.com/rmosolgo/graphql-ruby/issues/982.
208
- nil
209
- rescue StandardError => ex
210
- handle_extraction_exception(ex)
211
- end
212
-
213
- def extract_node(irep_node)
214
- extract_field(irep_node)
215
- extract_arguments(irep_node)
216
-
217
- irep_node.scoped_children.each_value do |children|
218
- children.each_value do |child_irep_node|
219
- extract_node(child_irep_node)
220
- end
221
- end
222
- rescue StandardError => ex
223
- handle_extraction_exception(ex)
224
- end
225
-
226
- def traverse_arguments(value, irep_node, types = [])
227
- case value
228
- when Array
229
- value.each do |v|
230
- traverse_arguments(v, irep_node, types)
231
- end
232
- when Hash
233
- value.each_value do |v|
234
- traverse_arguments(v, irep_node, types)
235
- end
236
- when ::GraphQL::Query::Arguments
237
- value.each_value do |arg_val|
238
- traverse_arguments(arg_val, irep_node, types)
239
- end
240
- when ::GraphQL::Query::Arguments::ArgumentValue
241
- extract_argument(value, irep_node, types)
242
- traverse_arguments(value.value, irep_node, types + [value.definition.type])
243
- when ::GraphQL::Schema::InputObject
244
- traverse_arguments(value.arguments.argument_values.values, irep_node, types)
245
- end
246
- rescue StandardError => ex
247
- handle_extraction_exception(ex)
248
- end
249
-
250
- def unwrapped_type(type)
251
- if type.is_a?(GraphQL::Language::Nodes::WrapperType)
252
- unwrapped_type(type.of_type)
253
- else
254
- type.name
255
- end
256
- rescue StandardError => ex
257
- handle_extraction_exception(ex)
258
- end
259
-
260
- def extraction_method(method_name)
261
- @extraction_method_cache ||= {}
262
- return @extraction_method_cache[method_name] if @extraction_method_cache.has_key?(method_name)
263
-
264
- method = if respond_to?(method_name)
265
- method(method_name)
266
- elsif instrumentor && instrumentor.respond_to?(method_name)
267
- instrumentor.method(method_name)
268
- else
269
- nil
270
- end
271
-
272
- method.tap do |method|
273
- @extraction_method_cache[method_name] = method
274
- end
275
- end
276
- end
277
- end