graphql-metrics 4.0.6 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 794d916d7f0b35ed8c50814c7cee54af5881a9fa5102eb361d1486fde665b413
4
- data.tar.gz: 831cd8c26e771fc5e97e483f5cda86bce63311c0a31a9d12a020cdf5be808241
3
+ metadata.gz: 7c32ac33ad3d4dcce935518115cb51e8b619b4f06e5eaacf6eded57b0393e8d1
4
+ data.tar.gz: 466c20309ac8e7ca599580f9145c936bbcb76cb29c9f019fa28c3be3c9c46ba7
5
5
  SHA512:
6
- metadata.gz: aed42769f9dcbcb445e0e9b8ec9858d05c917542fa0c588bcc587d19c2fbc8bafd2d1fcf65f4d7742cd498a2ac1d39b66c6955827efa4da3582a44980f2346e1
7
- data.tar.gz: 908bc4cf5d126d71e715379cd2346308b5e7ed17230ad4733eff2614827625768d0ec1186da282628c91c6ab3fe7dd3a92adc6b6e9e548b202eb3b9507f6a8fd
6
+ metadata.gz: fc8fa91436e89b75faa0573007bb20ce3a381019231dcb6131f41a73395b4c62c990be07efadbf437c9f1c67f9a9a03ef328c3d379e57132dcee00332489bf7f
7
+ data.tar.gz: d465979e9f3b3ea7b7f17c0275a48bd629ab45f80eeb89e69dc7d8040dd8f615e7a23bfefdab0befb04402d192e11dfb818417c65f930dd8fdcdd3eae030715b
data/.gitignore CHANGED
@@ -7,5 +7,5 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  *.gem
10
-
10
+ Gemfile.lock
11
11
  /vendor/
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ 4.1.0
2
+ -----
3
+ - [42](https://github.com/Shopify/graphql-metrics/pull/42) Capture timing of the `lex` phase.
4
+
1
5
  4.0.6
2
6
  -----
3
7
  - [35](https://github.com/Shopify/graphql-metrics/pull/35) Fix query start time, start time offset bugs.
data/README.md CHANGED
@@ -7,6 +7,9 @@ Compatible with the [`graphql-batch` gem](https://github.com/Shopify/graphql-bat
7
7
 
8
8
  Be sure to read the [CHANGELOG](CHANGELOG.md) to stay updated on feature additions, breaking changes made to this gem.
9
9
 
10
+ **NOTE**: Not tested with graphql-ruby's multiplexing feature. Metrics may not
11
+ be accurate if you execute multiple operations at once.
12
+
10
13
  ## Installation
11
14
 
12
15
  Add this line to your application's Gemfile:
@@ -44,13 +47,11 @@ etc.
44
47
 
45
48
  What you do with these captured metrics is up to you!
46
49
 
47
- **NOTE**: Runtime metrics on for queries (like `query_duration`, `parsing_start_time_offset` etc.) as well as field
48
- resolver timings (like `resolver_timings`, `lazy_resolver_timings`) may not be present in the extracted `metrics` hash,
50
+ **NOTE**: If any non-`graphql-ruby` gem-related exceptions occur in your application during query document
51
+ parsing and validation, **runtime metrics** for queries (like `query_duration`, `parsing_start_time_offset` etc.) as well as field
52
+ resolver timings (like `resolver_timings`, `lazy_resolver_timings`) **may not be present** in the extracted `metrics` hash,
49
53
  even if you opt to collect them by using `GraphQL::Metrics::Analyzer` and `GraphQL::Metrics::Tracer`.
50
54
 
51
- More specifically, if any non-`graphql-ruby` gem-related exceptions occur in your application during query document
52
- parsing and validation runtime metrics will not be added to the `metrics` hash.
53
-
54
55
  ### Define your own analyzer subclass
55
56
 
56
57
  ```ruby
@@ -74,6 +75,8 @@ parsing and validation runtime metrics will not be added to the `metrics` hash.
74
75
  # operation_name: "PostDetails",
75
76
  # query_start_time: 1573833076.027327,
76
77
  # query_duration: 2.0207119999686256,
78
+ # lexing_start_time_offset: 0.0010339999571442604,
79
+ # lexing_duration: 0.0008190000080503523,
77
80
  # parsing_start_time_offset: 0.0010339999571442604,
78
81
  # parsing_duration: 0.0008190000080503523,
79
82
  # validation_start_time_offset: 0.0030819999519735575,
@@ -181,9 +184,6 @@ class Schema < GraphQL::Schema
181
184
  query QueryRoot
182
185
  mutation MutationRoot
183
186
 
184
- use GraphQL::Execution::Interpreter # Required.
185
- use GraphQL::Analysis::AST # Required.
186
-
187
187
  query_analyzer SimpleAnalyzer
188
188
 
189
189
  instrument :query, GraphQL::Metrics::Instrumentation.new # Both of these are required if either is used.
@@ -203,9 +203,6 @@ class Schema < GraphQL::Schema
203
203
  query QueryRoot
204
204
  mutation MutationRoot
205
205
 
206
- use GraphQL::Execution::Interpreter # Required.
207
- use GraphQL::Analysis::AST # Required.
208
-
209
206
  query_analyzer SimpleAnalyzer
210
207
  end
211
208
  ```
@@ -224,13 +221,15 @@ your application as intended, here's a breakdown of the order of execution of th
224
221
 
225
222
  When used as instrumentation, an analyzer and tracing, the order of execution is:
226
223
 
227
- * Tracer.setup_tracing
224
+ * Tracer.capture_lexing_time
228
225
  * Tracer.capture_parsing_time
226
+ * Tracer.capture_multiplex_start_time
229
227
  * Instrumentation.before_query (context setup)
230
228
  * Tracer.capture_validation_time
231
229
  * Tracer.capture_analysis_time
232
230
  * Analyzer#initialize (bit more context setup, instance vars setup)
233
231
  * Analyzer#result
232
+ * Tracer.capture_query_start_time
234
233
  * Tracer.trace_field (n times)
235
234
  * Instrumentation.after_query (call query and field callbacks, now that we have all static and runtime metrics
236
235
  gathered)
@@ -254,7 +253,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
254
253
 
255
254
  ## Contributing
256
255
 
257
- Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/graphql_metrics. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
256
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/graphql-metrics. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
258
257
 
259
258
  ## License
260
259
 
@@ -26,6 +26,8 @@ module GraphQL
26
26
  MULTIPLEX_START_TIME_MONOTONIC = :multiplex_start_time_monotonic
27
27
  QUERY_START_TIME = :query_start_time
28
28
  QUERY_START_TIME_MONOTONIC = :query_start_time_monotonic
29
+ LEXING_START_TIME_OFFSET = :lexing_start_time_offset
30
+ LEXING_DURATION = :lexing_duration
29
31
  PARSING_START_TIME_OFFSET = :parsing_start_time_offset
30
32
  PARSING_DURATION = :parsing_duration
31
33
  VALIDATION_START_TIME_OFFSET = :validation_start_time_offset
@@ -45,6 +45,8 @@ module GraphQL
45
45
  parsing_duration: ns[GraphQL::Metrics::PARSING_DURATION],
46
46
  validation_start_time_offset: ns[GraphQL::Metrics::VALIDATION_START_TIME_OFFSET],
47
47
  validation_duration: ns[GraphQL::Metrics::VALIDATION_DURATION],
48
+ lexing_start_time_offset: ns[GraphQL::Metrics::LEXING_START_TIME_OFFSET],
49
+ lexing_duration: ns[GraphQL::Metrics::LEXING_DURATION],
48
50
  analysis_start_time_offset: ns[GraphQL::Metrics::ANALYSIS_START_TIME_OFFSET],
49
51
  analysis_duration: ns[GraphQL::Metrics::ANALYSIS_DURATION],
50
52
  multiplex_start_time: ns[GraphQL::Metrics::MULTIPLEX_START_TIME],
@@ -3,11 +3,13 @@
3
3
  module GraphQL
4
4
  module Metrics
5
5
  class Tracer
6
- # NOTE: These constants come from the graphql ruby gem.
7
- GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY = 'execute_multiplex'
8
- GRAPHQL_GEM_PARSING_KEY = 'parse'
6
+ # NOTE: These constants come from the graphql ruby gem and are in "chronological" order based on the phases
7
+ # of execution of the graphql-ruby gem. Most of them can be run multiple times when multiplexing multiple queries.
8
+ GRAPHQL_GEM_LEXING_KEY = 'lex' # may not trigger if the query is passed in pre-parsed
9
+ GRAPHQL_GEM_PARSING_KEY = 'parse' # may not trigger if the query is passed in pre-parsed
10
+ GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY = 'execute_multiplex' # wraps everything below this line; only run once
9
11
  GRAPHQL_GEM_VALIDATION_KEY = 'validate'
10
- GRAPHQL_GEM_ANALYZE_MULTIPLEX_KEY = 'analyze_multiplex'
12
+ GRAPHQL_GEM_ANALYZE_MULTIPLEX_KEY = 'analyze_multiplex' # wraps all `analyze_query`s; only run once
11
13
  GRAPHQL_GEM_ANALYZE_QUERY_KEY = 'analyze_query'
12
14
  GRAPHQL_GEM_EXECUTE_QUERY_KEY = 'execute_query'
13
15
  GRAPHQL_GEM_TRACING_FIELD_KEYS = [
@@ -17,20 +19,18 @@ module GraphQL
17
19
 
18
20
  def trace(key, data, &block)
19
21
  # NOTE: Context doesn't exist yet during lexing, parsing.
20
- possible_context = data[:query]&.context
21
-
22
- skip_tracing = possible_context&.fetch(GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS, false)
22
+ context = data[:query]&.context
23
+ skip_tracing = context&.fetch(GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS, false)
23
24
  return yield if skip_tracing
24
25
 
25
- # NOTE: Not all tracing events are handled here, but those that are are handled in this case statement in
26
- # chronological order.
27
26
  case key
28
- when GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY
29
- return capture_multiplex_start_time(&block)
27
+ when GRAPHQL_GEM_LEXING_KEY
28
+ return capture_lexing_time(&block)
30
29
  when GRAPHQL_GEM_PARSING_KEY
31
30
  return capture_parsing_time(&block)
31
+ when GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY
32
+ return capture_multiplex_start_time(&block)
32
33
  when GRAPHQL_GEM_VALIDATION_KEY
33
- context = possible_context
34
34
  return capture_validation_time(context, &block)
35
35
  when GRAPHQL_GEM_ANALYZE_MULTIPLEX_KEY
36
36
  # Ensures that we reset potentially long-lived PreContext objects between multiplexs. We reset at this point
@@ -38,13 +38,11 @@ module GraphQL
38
38
  pre_context.reset
39
39
  return yield
40
40
  when GRAPHQL_GEM_ANALYZE_QUERY_KEY
41
- context = possible_context
42
41
  return capture_analysis_time(context, &block)
43
42
  when GRAPHQL_GEM_EXECUTE_QUERY_KEY
44
- context = possible_context
45
43
  capture_query_start_time(context, &block)
46
44
  when *GRAPHQL_GEM_TRACING_FIELD_KEYS
47
- return yield if data[:query].context[SKIP_FIELD_AND_ARGUMENT_METRICS]
45
+ return yield if context[SKIP_FIELD_AND_ARGUMENT_METRICS]
48
46
  return yield unless GraphQL::Metrics.timings_capture_enabled?(data[:query].context)
49
47
 
50
48
  context_key = case key
@@ -66,7 +64,9 @@ module GraphQL
66
64
  :multiplex_start_time,
67
65
  :multiplex_start_time_monotonic,
68
66
  :parsing_start_time_offset,
69
- :parsing_duration
67
+ :parsing_duration,
68
+ :lexing_start_time_offset,
69
+ :lexing_duration
70
70
  ) do
71
71
  def reset
72
72
  self[:multiplex_start_time] = nil
@@ -90,6 +90,18 @@ module GraphQL
90
90
  yield
91
91
  end
92
92
 
93
+ def capture_lexing_time
94
+ # GraphQL::Query#result fires `lex` before the `execute_multiplex` event, so sometimes
95
+ # `pre_context.multiplex_start_time_monotonic` isn't set.
96
+ lexing_offset_time = pre_context.multiplex_start_time_monotonic || GraphQL::Metrics.current_time_monotonic
97
+ timed_result = GraphQL::Metrics.time(lexing_offset_time) { yield }
98
+
99
+ pre_context.lexing_start_time_offset = timed_result.start_time
100
+ pre_context.lexing_duration = timed_result.duration
101
+
102
+ timed_result.result
103
+ end
104
+
93
105
  def capture_parsing_time
94
106
  # GraphQL::Query#result fires `parse` before the `execute_multiplex` event, so sometimes
95
107
  # `pre_context.multiplex_start_time_monotonic` isn't set.
@@ -104,12 +116,14 @@ module GraphQL
104
116
 
105
117
  # Also consolidates parsing timings (if any) from the `pre_context`
106
118
  def capture_validation_time(context)
119
+ # Queries may already be lexed and parsed before execution (whether a single query or multiplex).
120
+ # If we don't have those values, use some sane defaults.
121
+ if pre_context.lexing_duration.nil?
122
+ pre_context.lexing_start_time_offset = pre_context.multiplex_start_time
123
+ pre_context.lexing_duration = 0.0
124
+ end
107
125
  if pre_context.parsing_duration.nil?
108
- # Queries may already be parsed before execution (whether a single query or multiplex).
109
- # If we don't have a parsing start time, use the multiplex start time.
110
126
  pre_context.parsing_start_time_offset = pre_context.multiplex_start_time
111
-
112
- # If we don't have a duration, consider parsing to have been instantaneous.
113
127
  pre_context.parsing_duration = 0.0
114
128
  end
115
129
 
@@ -119,6 +133,8 @@ module GraphQL
119
133
 
120
134
  ns[MULTIPLEX_START_TIME] = pre_context.multiplex_start_time
121
135
  ns[MULTIPLEX_START_TIME_MONOTONIC] = pre_context.multiplex_start_time_monotonic
136
+ ns[LEXING_START_TIME_OFFSET] = pre_context.lexing_start_time_offset
137
+ ns[LEXING_DURATION] = pre_context.lexing_duration
122
138
  ns[PARSING_START_TIME_OFFSET] = pre_context.parsing_start_time_offset
123
139
  ns[PARSING_DURATION] = pre_context.parsing_duration
124
140
  ns[VALIDATION_START_TIME_OFFSET] = timed_result.time_since_offset
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module Metrics
5
- VERSION = "4.0.6"
5
+ VERSION = "4.1.0"
6
6
  end
7
7
  end
data/service.yml ADDED
@@ -0,0 +1 @@
1
+ classification: library
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.6
4
+ version: 4.1.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: 2020-08-20 00:00:00.000000000 Z
11
+ date: 2021-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -209,7 +209,6 @@ files:
209
209
  - CHANGELOG.md
210
210
  - CODE_OF_CONDUCT.md
211
211
  - Gemfile
212
- - Gemfile.lock
213
212
  - LICENSE.txt
214
213
  - README.md
215
214
  - RELEASING
@@ -222,6 +221,7 @@ files:
222
221
  - lib/graphql/metrics/instrumentation.rb
223
222
  - lib/graphql/metrics/tracer.rb
224
223
  - lib/graphql/metrics/version.rb
224
+ - service.yml
225
225
  homepage: https://github.com/Shopify/graphql-metrics
226
226
  licenses:
227
227
  - MIT
@@ -241,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
241
241
  - !ruby/object:Gem::Version
242
242
  version: '0'
243
243
  requirements: []
244
- rubygems_version: 3.0.3
244
+ rubygems_version: 3.1.2
245
245
  signing_key:
246
246
  specification_version: 4
247
247
  summary: GraphQL Metrics Extractor
data/Gemfile.lock DELETED
@@ -1,67 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- graphql-metrics (4.0.6)
5
- concurrent-ruby (~> 1.1.0)
6
- graphql (>= 1.10.8)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- activesupport (5.1.7)
12
- concurrent-ruby (~> 1.0, >= 1.0.2)
13
- i18n (>= 0.7, < 2)
14
- minitest (~> 5.1)
15
- tzinfo (~> 1.1)
16
- byebug (11.0.1)
17
- coderay (1.1.2)
18
- concurrent-ruby (1.1.5)
19
- diffy (3.3.0)
20
- fakeredis (0.7.0)
21
- redis (>= 3.2, < 5.0)
22
- graphql (1.10.8)
23
- graphql-batch (0.4.2)
24
- graphql (>= 1.3, < 2)
25
- promise.rb (~> 0.7.2)
26
- hashdiff (1.0.0)
27
- i18n (1.7.0)
28
- concurrent-ruby (~> 1.0)
29
- metaclass (0.0.4)
30
- method_source (0.9.2)
31
- minitest (5.13.0)
32
- minitest-focus (1.1.2)
33
- minitest (>= 4, < 6)
34
- mocha (1.9.0)
35
- metaclass (~> 0.0.1)
36
- promise.rb (0.7.4)
37
- pry (0.12.2)
38
- coderay (~> 1.1.0)
39
- method_source (~> 0.9.0)
40
- pry-byebug (3.7.0)
41
- byebug (~> 11.0)
42
- pry (~> 0.10)
43
- rake (13.0.1)
44
- redis (4.1.3)
45
- thread_safe (0.3.6)
46
- tzinfo (1.2.5)
47
- thread_safe (~> 0.1)
48
-
49
- PLATFORMS
50
- ruby
51
-
52
- DEPENDENCIES
53
- activesupport (~> 5.1.5)
54
- diffy
55
- fakeredis
56
- graphql-batch
57
- graphql-metrics!
58
- hashdiff
59
- minitest (~> 5.0)
60
- minitest-focus
61
- mocha
62
- pry
63
- pry-byebug
64
- rake
65
-
66
- BUNDLED WITH
67
- 2.1.4