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 +4 -4
- data/.gitignore +1 -1
- data/CHANGELOG.md +4 -0
- data/README.md +12 -13
- data/lib/graphql/metrics.rb +2 -0
- data/lib/graphql/metrics/instrumentation.rb +2 -0
- data/lib/graphql/metrics/tracer.rb +36 -20
- data/lib/graphql/metrics/version.rb +1 -1
- data/service.yml +1 -0
- metadata +4 -4
- data/Gemfile.lock +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c32ac33ad3d4dcce935518115cb51e8b619b4f06e5eaacf6eded57b0393e8d1
|
4
|
+
data.tar.gz: 466c20309ac8e7ca599580f9145c936bbcb76cb29c9f019fa28c3be3c9c46ba7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc8fa91436e89b75faa0573007bb20ce3a381019231dcb6131f41a73395b4c62c990be07efadbf437c9f1c67f9a9a03ef328c3d379e57132dcee00332489bf7f
|
7
|
+
data.tar.gz: d465979e9f3b3ea7b7f17c0275a48bd629ab45f80eeb89e69dc7d8040dd8f615e7a23bfefdab0befb04402d192e11dfb818417c65f930dd8fdcdd3eae030715b
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
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**:
|
48
|
-
|
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.
|
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/
|
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
|
|
data/lib/graphql/metrics.rb
CHANGED
@@ -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
|
-
|
8
|
-
|
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
|
-
|
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
|
29
|
-
return
|
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
|
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
|
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
|
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:
|
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.
|
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
|