graphql-metrics 4.0.6 → 4.1.0

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 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