graphql-metrics 5.0.8 → 6.0.1

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: f54fe0807d964c7ddf402984339caf1c29ba21953db7090ecbf948051048e5ee
4
- data.tar.gz: 694a4221b1673386f3104cd8bc0c5e5518f95505cdbbf7330cb98ee7e555bf1a
3
+ metadata.gz: 315fadbeefcfba11dcde6e9f60786b414c6351e891800ac908bd491b40a50ecd
4
+ data.tar.gz: cae83709e2add17cf2534486932c504d216784402fae02c994afd911d0bb42be
5
5
  SHA512:
6
- metadata.gz: f35acb43fde5fdb41b00e2f5fa4e99c2d478bf062630320e521134c8190a0820d81bf0aad9edc3882690a08c5b323998fbc41d1c98542d130e726a1982211fd9
7
- data.tar.gz: 7c7d3874d910f1587e65f95c163a12d236e86b5b92b58cbaaa51061e7b0420092357c2f2af87c393fba65174e8ef76ab928a7da5fdc22d984c17740484032087
6
+ metadata.gz: f9e9b56eabf8f9993501b9bf805c05515ba5bba50e908f1aa10c205534208f1b60b6da90c3a2e951bb08fa6387860089decca0bcaea0b87649a5d42e5842cc6c
7
+ data.tar.gz: 3a513f4d6f25732972db556526bba42884ef41389cee0f372a0bd373ce71853889ea70e4cad5c042ad3956f3ea4e22cbbc1d5871f9d340e6e433499a7ffbbde2
@@ -0,0 +1,24 @@
1
+ version: 2
2
+ registries:
3
+ ruby-shopify:
4
+ type: rubygems-server
5
+ url: https://pkgs.shopify.io/basic/gems/ruby
6
+ username: ${{secrets.RUBYGEMS_SERVER_PKGS_SHOPIFY_IO_USERNAME}}
7
+ password: ${{secrets.RUBYGEMS_SERVER_PKGS_SHOPIFY_IO_PASSWORD}}
8
+ github-com:
9
+ type: git
10
+ url: https://github.com
11
+ username: ${{secrets.DEPENDENCIES_GITHUB_USER}}
12
+ password: ${{secrets.DEPENDENCIES_GITHUB_TOKEN}}
13
+ updates:
14
+ - package-ecosystem: github-actions
15
+ directory: "/"
16
+ schedule:
17
+ interval: weekly
18
+ - package-ecosystem: bundler
19
+ directory: "/"
20
+ schedule:
21
+ interval: weekly
22
+ open-pull-requests-limit: 100
23
+ insecure-external-code-execution: allow
24
+ registries: "*"
@@ -0,0 +1,23 @@
1
+ name: Dependabot auto-merge
2
+ on: pull_request_target
3
+
4
+ permissions:
5
+ pull-requests: write
6
+ contents: write
7
+
8
+ jobs:
9
+ dependabot:
10
+ runs-on: ubuntu-latest
11
+ if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
12
+ steps:
13
+ - name: Dependabot metadata
14
+ id: metadata
15
+ uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
16
+ with:
17
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
18
+ - name: Enable auto-merge for Dependabot PRs
19
+ if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }}
20
+ run: gh pr merge --auto --merge "$PR_URL"
21
+ env:
22
+ PR_URL: ${{ github.event.pull_request.html_url }}
23
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,52 @@
1
+ name: Release gem on RubyGems.org and create GitHub release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v[0-9]+.[0-9]+.[0-9]+'
7
+
8
+ jobs:
9
+ release_gem:
10
+ name: Release gem on RubyGems.org
11
+ if: github.repository == 'Shopify/graphql-metrics'
12
+ runs-on: ubuntu-latest
13
+
14
+ permissions:
15
+ contents: write
16
+ id-token: write
17
+
18
+ environment: release
19
+
20
+ steps:
21
+ - name: Checkout repository
22
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@b3aaceaef7e0ee231b499e7b5f49c03fc1d32199 # v1.338.0
28
+ with:
29
+ bundler-cache: true
30
+
31
+ - name: Release gem on RubyGems.org
32
+ uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
33
+
34
+ release_github:
35
+ name: Create GitHub release
36
+ if: github.repository == 'Shopify/graphql-metrics'
37
+ needs: release_gem
38
+ runs-on: ubuntu-latest
39
+
40
+ permissions:
41
+ contents: write
42
+
43
+ steps:
44
+ - name: Checkout repository
45
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
46
+ with:
47
+ persist-credentials: false
48
+
49
+ - name: Create GitHub release
50
+ run: gh release create "${GITHUB_REF_NAME}" --verify-tag --generate-notes
51
+ env:
52
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,19 +1,23 @@
1
1
  name: Tests
2
- on: [push, pull_request]
2
+ on:
3
+ push:
4
+ pull_request:
5
+ schedule:
6
+ - cron: '0 8 * * 1'
3
7
  jobs:
4
8
  test:
5
9
  strategy:
6
10
  fail-fast: false
7
11
  matrix:
8
12
  os: [ubuntu-latest]
9
- ruby: ['2.7', '3.0', '3.1', '3.2']
10
- gemfile: ['graphql_1.13', 'graphql_2.0', 'graphql_head']
13
+ ruby: ['3.3', '3.4', '4.0']
14
+ gemfile: ['graphql_2.3', 'graphql_head']
11
15
  runs-on: ${{ matrix.os }}
12
16
  env:
13
17
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
14
18
  steps:
15
- - uses: actions/checkout@v3
16
- - uses: ruby/setup-ruby@v1
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
+ - uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
17
21
  with:
18
22
  ruby-version: ${{ matrix.ruby }}
19
23
  bundler-cache: true
data/.gitignore CHANGED
@@ -7,5 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  *.gem
10
- Gemfile.lock
11
10
  /vendor/
data/.rubocop.yml CHANGED
@@ -1,5 +1,2 @@
1
1
  inherit_from:
2
2
  - http://shopify.github.io/ruby-style-guide/rubocop.yml
3
-
4
- AllCops:
5
- TargetRubyVersion: 2.6
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 4.0.9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ 6.0.1
2
+ -----
3
+ - [149](https://github.com/Shopify/graphql-metrics/pull/149) Require Ruby 3.3 or newer
4
+ - [110](https://github.com/Shopify/graphql-metrics/pull/110) Fix missing `parent_input_object_type` in nested input object metrics
5
+
6
+ 6.0.0
7
+ -----
8
+
9
+ **Usage change**
10
+ Due to Instrumentation plugins being deprecated in the `graphql` gem, `graphql-metrics` has been refactored to use the [new `Tracing` API](https://graphql-ruby.org/queries/tracing.html).
11
+ This changes how `graphql-metrics` is used in your application.
12
+
13
+ Before:
14
+ ```ruby
15
+ class MySchema < GraphQL::Schema
16
+ instrument :query, GraphQLMetrics::Instrumentation.new
17
+ query_analyzer MyMetricsAnalyzer
18
+ tracer GraphQL::Metrics::Tracer.new
19
+ end
20
+ ```
21
+
22
+ After:
23
+ ```ruby
24
+ class MySchema < GraphQL::Schema
25
+ use GraphQL::Metrics, analyzer: MyMetricsAnalyzer
26
+ end
27
+ ```
28
+
29
+ Other breaking changes:
30
+ * `graphql` >= 2.3 is now required.
31
+ * Apollo tracing spec support has been removed (the spec has been deprecated for years). All `start_time_offset` metrics have been removed.
32
+ * Support for the old tracing API has been removed.
33
+ * The `multiplex_start_time_monotonic` operation mettric has been removed.
34
+
35
+
36
+ Changes:
37
+ - [87](https://github.com/Shopify/graphql-metrics/pull/87) Migrate Instrumentation to tracing
38
+ - [88](https://github.com/Shopify/graphql-metrics/pull/88) Update `analyzer` option
39
+ - [86](https://github.com/Shopify/graphql-metrics/pull/86) Refactor static metric mode
40
+ - [85](https://github.com/Shopify/graphql-metrics/pull/85) Remove old tracing API support
41
+ - [84](https://github.com/Shopify/graphql-metrics/pull/84) Remove Apollo tracing spec support
42
+ - [80](https://github.com/Shopify/graphql-metrics/pull/80) Support new parser
43
+ - [79](https://github.com/Shopify/graphql-metrics/pull/79) Centralize Ruby Version to `.ruby-version`
44
+
1
45
  5.0.8
2
46
  -----
3
47
  - [76](https://github.com/Shopify/graphql-metrics/pull/76) Reduce object allocations
data/Gemfile.lock ADDED
@@ -0,0 +1,71 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ graphql-metrics (6.0.1)
5
+ graphql (>= 2.3)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ base64 (0.3.0)
11
+ byebug (13.0.0)
12
+ reline (>= 0.6.0)
13
+ coderay (1.1.3)
14
+ diffy (3.4.3)
15
+ drb (2.2.3)
16
+ fakeredis (0.9.2)
17
+ redis (~> 4.8)
18
+ fiber-storage (1.0.1)
19
+ graphql (2.4.18)
20
+ base64
21
+ fiber-storage
22
+ logger
23
+ graphql-batch (0.6.0)
24
+ graphql (>= 1.12.18, < 3)
25
+ promise.rb (~> 0.7.2)
26
+ hashdiff (1.1.2)
27
+ io-console (0.9.5)
28
+ logger (1.7.0)
29
+ method_source (1.1.0)
30
+ minitest (6.1.0)
31
+ drb (~> 2.0)
32
+ prism (>= 1.5, < 3)
33
+ minitest-focus (1.4.1)
34
+ minitest (> 5.0)
35
+ mocha (2.7.1)
36
+ ruby2_keywords (>= 0.0.5)
37
+ prism (2.1.0-arm64-darwin)
38
+ prism (2.1.0-x86_64-linux-gnu)
39
+ promise.rb (0.7.4)
40
+ pry (0.16.1)
41
+ coderay (~> 1.1)
42
+ method_source (~> 1.0)
43
+ reline (>= 0.6.0)
44
+ pry-byebug (3.12.0)
45
+ byebug (~> 13.0)
46
+ pry (>= 0.13, < 0.17)
47
+ rake (13.2.1)
48
+ redis (4.8.1)
49
+ reline (0.7.0)
50
+ io-console (~> 0.5)
51
+ ruby2_keywords (0.0.5)
52
+
53
+ PLATFORMS
54
+ arm64-darwin-23
55
+ x86_64-linux
56
+
57
+ DEPENDENCIES
58
+ diffy
59
+ fakeredis
60
+ graphql-batch
61
+ graphql-metrics!
62
+ hashdiff
63
+ minitest (~> 6.0)
64
+ minitest-focus
65
+ mocha
66
+ pry
67
+ pry-byebug
68
+ rake
69
+
70
+ BUNDLED WITH
71
+ 2.4.1
data/README.md CHANGED
@@ -7,9 +7,6 @@ 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
-
13
10
  ## Installation
14
11
 
15
12
  Add this line to your application's Gemfile:
@@ -42,15 +39,15 @@ Get started by defining your own Analyzer, inheriting from `GraphQL::Metrics::An
42
39
 
43
40
  The following analyzer demonstrates a simple way to capture commonly used metrics sourced from key parts of your schema
44
41
  definition, the query document being served, as well as runtime query and resolver timings. In this toy example, all of
45
- this data is simply stored on the GraphQL::Query context, under a namespace to avoid collisions with other analyzers
42
+ this data is simply stored on the `GraphQL::Query` context, under a namespace to avoid collisions with other analyzers
46
43
  etc.
47
44
 
48
45
  What you do with these captured metrics is up to you!
49
46
 
50
47
  **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
48
+ parsing and validation, **runtime metrics** for queries (like `query_duration`, etc.) as well as field
52
49
  resolver timings (like `resolver_timings`, `lazy_resolver_timings`) **may not be present** in the extracted `metrics` hash,
53
- even if you opt to collect them by using `GraphQL::Metrics::Analyzer` and `GraphQL::Metrics::Tracer`.
50
+ even if you opt to collect them.
54
51
 
55
52
  ### Define your own analyzer subclass
56
53
 
@@ -75,15 +72,10 @@ even if you opt to collect them by using `GraphQL::Metrics::Analyzer` and `Graph
75
72
  # operation_name: "PostDetails",
76
73
  # query_start_time: 1573833076.027327,
77
74
  # query_duration: 2.0207119999686256,
78
- # lexing_start_time_offset: 0.0010339999571442604,
79
75
  # lexing_duration: 0.0008190000080503523,
80
- # parsing_start_time_offset: 0.0010339999571442604,
81
76
  # parsing_duration: 0.0008190000080503523,
82
- # validation_start_time_offset: 0.0030819999519735575,
83
77
  # validation_duration: 0.01704599999357015,
84
- # analysis_start_time_offset: 0.0010339999571442604,
85
78
  # analysis_duration: 0.0008190000080503523,
86
- # multiplex_start_time: 0.0008190000080503523,
87
79
  # }
88
80
  #
89
81
  # You can use these metrics to track high-level query performance, along with any other details you wish to
@@ -129,12 +121,10 @@ even if you opt to collect them by using `GraphQL::Metrics::Analyzer` and `Graph
129
121
  # deprecated: false,
130
122
  # path: ["post", "id"],
131
123
  # resolver_timings: [
132
- # start_time_offset: 0.011901999998372048,
133
- # duration: 5.999987479299307e-06
124
+ # 5.999987479299307e-06,
134
125
  # ],
135
126
  # lazy_resolver_timings: [
136
- # start_time_offset: 0.031901999998372048,
137
- # duration: 5.999987479299307e-06
127
+ # 5.999987479299307e-06,
138
128
  # ],
139
129
  # }
140
130
  def field_extracted(metrics)
@@ -178,12 +168,12 @@ even if you opt to collect them by using `GraphQL::Metrics::Analyzer` and `Graph
178
168
  end
179
169
  ```
180
170
 
181
- Once defined, you can opt into capturing all metrics seen above by simply including GraphQL::Metrics as a plugin on your
171
+ Once defined, you can opt into capturing all metrics seen above by simply including `GraphQL::Metrics` as a plugin on your
182
172
  schema.
183
- #### Metrics that are captured for arguments for fields and directives
184
173
 
185
- Let's have a query example
174
+ #### Metrics that are captured for arguments for fields and directives
186
175
 
176
+ Example query:
187
177
  ```graphql
188
178
  query PostDetails($postId: ID!, $commentsTags: [String!] = null, $val: Int!) @customDirective(val: $val) {
189
179
  post(id: $postId) {
@@ -242,46 +232,48 @@ These are some of the arguments that are extracted
242
232
 
243
233
  ### Make use of your analyzer
244
234
 
245
- Ensure that your schema is using the graphql-ruby 1.9+ `GraphQL::Execution::Interpreter` and `GraphQL::Analysis::AST`
246
- engine, and then simply add the below `GraphQL::Metrics` plugins.
247
-
248
- This opts you in to capturing all static and runtime metrics seen above.
235
+ Add the `GraphQL::Metrics` plugin to your schema. This opts you in to capturing all static and runtime metrics seen above.
249
236
 
250
237
  ```ruby
251
238
  class Schema < GraphQL::Schema
252
239
  query QueryRoot
253
240
  mutation MutationRoot
254
241
 
255
- query_analyzer SimpleAnalyzer
256
-
257
- instrument :query, GraphQL::Metrics::Instrumentation.new # Both of these are required if either is used.
258
- tracer GraphQL::Metrics::Tracer.new # <-- Note!
259
-
260
- use GraphQL::Batch # Optional, but highly recommended. See https://github.com/Shopify/graphql-batch/.
242
+ use GraphQL::Metrics, analyzer: SimpleAnalyzer
261
243
  end
262
244
  ```
263
245
 
264
246
  ### Optionally, only gather static metrics
265
247
 
266
- If you don't care to capture runtime metrics like query and resolver timings, you can use your analyzer a standalone
267
- analyzer without `GraphQL::Metrics::Instrumentation` and `tracer GraphQL::Metrics::Tracer`, like so:
248
+ If you don't care to capture field timings metrics, they can be disabled with the `capture_field_timings` option:
268
249
 
269
250
  ```ruby
270
251
  class Schema < GraphQL::Schema
271
252
  query QueryRoot
272
253
  mutation MutationRoot
273
254
 
274
- query_analyzer SimpleAnalyzer
255
+ use GraphQL::Metrics, analyzer: SimpleAnalyzer, capture_field_timings: false
275
256
  end
276
257
  ```
277
258
 
278
259
  Your analyzer will still be called with `query_extracted`, `field_extracted`, but with timings metrics omitted.
279
- `argument_extracted` will work exactly the same, whether instrumentation and tracing are used or not.
260
+ `argument_extracted` will work exactly the same.
261
+
262
+ And if you want to disable tracing metrics entirely, use the `capture_timings` option:
263
+
264
+ ```ruby
265
+ class Schema < GraphQL::Schema
266
+ query QueryRoot
267
+ mutation MutationRoot
268
+
269
+ use GraphQL::Metrics, analyzer: SimpleAnalyzer, capture_timings: false
270
+ end
271
+ ```
280
272
 
281
273
  ## Order of execution
282
274
 
283
275
  Because of the structure of graphql-ruby's plugin architecture, it may be difficult to build an intuition around the
284
- order in which methods defined on `GraphQL::Metrics::Instrumentation`, `GraphQL::Metrics::Tracer` and subclasses of
276
+ order in which methods defined on `GraphQL::Metrics::Instrumentation`, `GraphQL::Metrics::Trace` and subclasses of
285
277
  `GraphQL::Metrics::Analyzer` run.
286
278
 
287
279
  Although you ideally will not need to care about these details if you are simply using this gem to gather metrics in
@@ -289,30 +281,21 @@ your application as intended, here's a breakdown of the order of execution of th
289
281
 
290
282
  When used as instrumentation, an analyzer and tracing, the order of execution is usually:
291
283
 
292
- * Tracer.capture_multiplex_start_time
293
- * Tracer.capture_lexing_time
294
- * Tracer.capture_parsing_time
295
- * Instrumentation.before_query (context setup)
296
- * Tracer.capture_validation_time
297
- * Tracer.capture_analysis_time
284
+ * Instrumentation.execute_multiplex (context setup)
285
+ * Trace.capture_lexing_time
286
+ * Trace.capture_parsing_time
287
+ * Trace.capture_validation_time
288
+ * Trace.capture_analysis_time
298
289
  * Analyzer#initialize (bit more context setup, instance vars setup)
299
290
  * Analyzer#result
300
- * Tracer.capture_query_start_time
301
- * Tracer.trace_field (n times)
302
- * Instrumentation.after_query (call query and field callbacks, now that we have all static and runtime metrics
303
- gathered)
291
+ * Trace.capture_query_start_time
292
+ * Trace.trace_field (n times)
293
+ * Instrumentation.execute_multiplex (call query and field callbacks, now that we have all static and runtime metrics gathered)
304
294
  * Analyzer#extract_query
305
295
  * Analyzer#query_extracted
306
296
  * Analyzer#extract_fields_with_runtime_metrics
307
297
  * calls Analyzer#field_extracted n times
308
298
 
309
- When used as a simple analyzer, which doesn't gather or emit any runtime metrics (timings, arg values):
310
- * Analyzer#initialize
311
- * Analyzer#field_extracted n times
312
- * Analyzer#result
313
- * Analyzer#extract_query
314
- * Analyzer#query_extracted
315
-
316
299
  ## Development
317
300
 
318
301
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/RELEASING CHANGED
@@ -2,14 +2,14 @@ Releasing graphql-metrics
2
2
 
3
3
  1. Check the Semantic Versioning page for info on how to version the new release: http://semver.org
4
4
  2. Update VERSION in lib/graphql/metrics/version.rb
5
- 3. Add a CHANGELOG entry for the new release
6
- 4. Commit the changes with a commit message like "Packaging for release X.Y.Z"
7
- 5. Tag the release with the version (Leave REV blank for HEAD or provide a SHA)
8
- $ git tag vX.Y.Z REV
9
- 6. Push out the changes
10
- $ git push
11
- 7. Push out the tags
12
- $ git push --tags
13
- 8. Publish the gem
14
- $ gem build graphql_metrics.gemspec
15
- $ gem push graphql-metrics-X.Y.Z.gem
5
+ 3. Run `bundle install` so Gemfile.lock picks up the new version
6
+ 4. Add a CHANGELOG entry for the new release
7
+ 5. Open a pull request with a title like "Packaging for release X.Y.Z" and merge it
8
+ 6. Tag the merge commit on main with the version and push the tag
9
+ $ git checkout main && git pull
10
+ $ git tag vX.Y.Z
11
+ $ git push origin vX.Y.Z
12
+
13
+ Pushing the tag runs the Release workflow (.github/workflows/release.yml),
14
+ which publishes the gem to RubyGems.org with trusted publishing and creates
15
+ a GitHub release with generated notes. No RubyGems API key is needed.
@@ -2,4 +2,4 @@
2
2
 
3
3
  eval_gemfile("../Gemfile")
4
4
 
5
- gem("graphql", "~> 1.13")
5
+ gem("graphql", "~> 2.3")
@@ -14,6 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = 'https://github.com/Shopify/graphql-metrics'
15
15
  spec.license = "MIT"
16
16
 
17
+ spec.required_ruby_version = ">= 3.3"
18
+
17
19
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
20
 
19
21
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -23,12 +25,10 @@ Gem::Specification.new do |spec|
23
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
26
  spec.require_paths = ["lib"]
25
27
 
26
- spec.add_runtime_dependency "graphql", ">= 1.12.10"
27
- spec.add_runtime_dependency "concurrent-ruby", ">= 1.1.0"
28
- spec.add_development_dependency "rake", "~> 10.0"
29
- spec.add_development_dependency "minitest", "~> 5.0"
28
+ spec.add_runtime_dependency "graphql", ">= 2.3"
29
+ spec.add_development_dependency "rake", "~> 13.2"
30
+ spec.add_development_dependency "minitest", "~> 6.0"
30
31
  spec.add_development_dependency 'graphql-batch'
31
- spec.add_development_dependency "activesupport", "~> 5.1.5"
32
32
  spec.add_development_dependency "pry"
33
33
  spec.add_development_dependency "pry-byebug"
34
34
  spec.add_development_dependency "mocha"
@@ -51,20 +51,13 @@ module GraphQL
51
51
  path: visitor.response_path,
52
52
  }
53
53
 
54
- if GraphQL::Metrics.timings_capture_enabled?(query.context)
55
- @static_field_metrics << static_metrics
56
- else
57
- field_extracted(static_metrics)
58
- end
54
+ @static_field_metrics << static_metrics
59
55
  end
60
56
 
61
57
  def extract_fields(with_runtime_metrics: true)
62
- return if query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
63
-
64
58
  ns = query.context.namespace(CONTEXT_NAMESPACE)
65
59
 
66
60
  @static_field_metrics.each do |static_metrics|
67
-
68
61
  if with_runtime_metrics
69
62
  resolver_timings = ns[GraphQL::Metrics::INLINE_FIELD_TIMINGS][static_metrics[:path]]
70
63
  lazy_resolver_timings = ns[GraphQL::Metrics::LAZY_FIELD_TIMINGS][static_metrics[:path]]
@@ -89,14 +82,6 @@ module GraphQL
89
82
  end
90
83
 
91
84
  def result
92
- return if GraphQL::Metrics.timings_capture_enabled?(query.context)
93
- return if query.context[GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS]
94
-
95
- # NOTE: If we're running as a static analyzer (i.e. not with instrumentation and tracing), we still need to
96
- # flush static query metrics somewhere other than `after_query`.
97
- ns = query.context.namespace(CONTEXT_NAMESPACE)
98
- analyzer = ns[GraphQL::Metrics::ANALYZER_INSTANCE_KEY]
99
- analyzer.extract_query
100
85
  end
101
86
 
102
87
  private
@@ -145,10 +130,19 @@ module GraphQL
145
130
  parent_input_object: parent_input_object,
146
131
  parent: parent
147
132
  )
133
+
134
+ # For nested InputObject arguments, we need to pass the InputObject type as the parent
135
+ # for its child fields to be properly attributed
136
+ parent_for_nested_fields = if argument.value.is_a?(::GraphQL::Schema::InputObject)
137
+ argument.value.class
138
+ else
139
+ parent_input_object
140
+ end
141
+
148
142
  extract_arguments(
149
- argument:argument.value,
143
+ argument: argument.value,
150
144
  definition: definition,
151
- parent_input_object: parent_input_object,
145
+ parent_input_object: parent_for_nested_fields,
152
146
  parent: parent
153
147
  )
154
148
  when ::GraphQL::Schema::InputObject
@@ -2,28 +2,39 @@
2
2
 
3
3
  module GraphQL
4
4
  module Metrics
5
- class Instrumentation
6
- def before_query(query)
7
- unless query_present_and_valid?(query)
8
- # Setting this prevents Analyzer and Tracer from trying to gather runtime metrics for invalid queries.
9
- query.context[GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS] = true
5
+ module Instrumentation
6
+ def initialize(capture_field_timings: true, **_options)
7
+ @capture_field_timings = capture_field_timings
8
+
9
+ super
10
+ end
11
+
12
+ def execute_multiplex(multiplex:)
13
+ return super if multiplex.context[GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS]
14
+
15
+ result = nil
16
+
17
+ multiplex.queries.each do |query|
18
+ ns = query.context.namespace(CONTEXT_NAMESPACE)
19
+ ns[GraphQL::Metrics::TIMINGS_CAPTURE_ENABLED] = @capture_field_timings
20
+ ns[GraphQL::Metrics::INLINE_FIELD_TIMINGS] = Hash.new { |h, k| h[k] = [] }
21
+ ns[GraphQL::Metrics::LAZY_FIELD_TIMINGS] = Hash.new { |h, k| h[k] = [] }
10
22
  end
11
23
 
12
- # Even if queries are present and valid, applications may set this context value in order to opt out of
13
- # having Analyzer and Tracer gather runtime metrics.
14
- # If we're skipping runtime metrics, then both Instrumentation before_ and after_query can and should be
15
- # short-circuited as well.
16
- return if query.context[GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS]
24
+ begin
25
+ result = super
26
+ ensure
27
+ multiplex.queries.each do |query|
28
+ handle_query(query) if query.valid?
29
+ end
30
+ end
17
31
 
18
- ns = query.context.namespace(CONTEXT_NAMESPACE)
19
- ns[GraphQL::Metrics::TIMINGS_CAPTURE_ENABLED] = true
20
- ns[GraphQL::Metrics::INLINE_FIELD_TIMINGS] = {}
21
- ns[GraphQL::Metrics::LAZY_FIELD_TIMINGS] = {}
32
+ result
22
33
  end
23
34
 
24
- def after_query(query)
25
- return if query.context[GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS]
35
+ private
26
36
 
37
+ def handle_query(query)
27
38
  ns = query.context.namespace(CONTEXT_NAMESPACE)
28
39
  analyzer = ns[GraphQL::Metrics::ANALYZER_INSTANCE_KEY]
29
40
 
@@ -41,30 +52,19 @@ module GraphQL
41
52
  runtime_query_metrics = {
42
53
  query_start_time: ns[GraphQL::Metrics::QUERY_START_TIME],
43
54
  query_duration: query_duration,
44
- parsing_start_time_offset: ns[GraphQL::Metrics::PARSING_START_TIME_OFFSET],
45
55
  parsing_duration: ns[GraphQL::Metrics::PARSING_DURATION],
46
- validation_start_time_offset: ns[GraphQL::Metrics::VALIDATION_START_TIME_OFFSET],
47
56
  validation_duration: ns[GraphQL::Metrics::VALIDATION_DURATION],
48
- lexing_start_time_offset: ns[GraphQL::Metrics::LEXING_START_TIME_OFFSET],
49
57
  lexing_duration: ns[GraphQL::Metrics::LEXING_DURATION],
50
- analysis_start_time_offset: ns[GraphQL::Metrics::ANALYSIS_START_TIME_OFFSET],
51
58
  analysis_duration: ns[GraphQL::Metrics::ANALYSIS_DURATION],
52
- multiplex_start_time: ns[GraphQL::Metrics::MULTIPLEX_START_TIME],
53
59
  }
54
60
 
55
- analyzer.extract_fields
61
+ analyzer.extract_fields(with_runtime_metrics: @capture_field_timings)
56
62
  analyzer.extract_query(runtime_query_metrics: runtime_query_metrics)
57
63
  end
58
64
  end
59
65
 
60
66
  private
61
67
 
62
- def query_present_and_valid?(query)
63
- # Check for selected_operation as well for graphql 1.9 compatibility
64
- # which did not reject "empty" documents in its parser.
65
- query.valid? && !query.selected_operation.nil?
66
- end
67
-
68
68
  def runtime_metrics_interrupted?(context_namespace)
69
69
  # NOTE: The start time stored at `ns[GraphQL::Metrics::QUERY_START_TIME_MONOTONIC]` is captured during query
70
70
  # parsing, which occurs before `Instrumentation#before_query`.
@@ -8,6 +8,8 @@ module GraphQL
8
8
 
9
9
  query_or_multiplex = @query || @multiplex
10
10
  @skip_tracing = query_or_multiplex.context&.fetch(SKIP_GRAPHQL_METRICS_ANALYSIS, false) if query_or_multiplex
11
+ @parsing_duration = 0.0
12
+ @lexing_duration = 0.0
11
13
  end
12
14
 
13
15
  # NOTE: These methods come from the graphql ruby gem and are in "chronological" order based on the phases
@@ -15,12 +17,6 @@ module GraphQL
15
17
  # https://github.com/rmosolgo/graphql-ruby/issues/3393). Most of them can be run multiple times when
16
18
  # multiplexing multiple queries.
17
19
 
18
- # wraps everything below this line; only run once
19
- def execute_multiplex(multiplex:)
20
- return super if skip_tracing?(multiplex)
21
- capture_multiplex_start_time { super }
22
- end
23
-
24
20
  # may not trigger if the query is passed in pre-parsed
25
21
  def lex(query_string:)
26
22
  return super if @skip_tracing
@@ -34,139 +30,74 @@ module GraphQL
34
30
  end
35
31
 
36
32
  def validate(query:, validate:)
37
- return super if skip_tracing?(query)
33
+ return super if @skip_tracing
38
34
  capture_validation_time(query.context) { super }
39
35
  end
40
36
 
41
- # wraps all `analyze_query`s; only run once
42
- def analyze_multiplex(multiplex:)
43
- return super if skip_tracing?(multiplex)
44
- # Ensures that we reset potentially long-lived PreContext objects between multiplexs. We reset at this point
45
- # since all parsing and validation will be done by this point, and a GraphQL::Query::Context will exist.
46
- pre_context.reset
47
- super
48
- end
49
-
50
37
  def analyze_query(query:)
51
- return super if skip_tracing?(query)
38
+ return super if @skip_tracing
52
39
  capture_analysis_time(query.context) { super }
53
40
  end
54
41
 
55
42
  def execute_query(query:)
56
- return super if skip_tracing?(query)
43
+ return super if @skip_tracing
57
44
  capture_query_start_time(query.context) { super }
58
45
  end
59
46
 
60
47
  def execute_field(field:, query:, ast_node:, arguments:, object:)
61
- return super if skip_tracing?(query) || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
62
- return super unless GraphQL::Metrics.timings_capture_enabled?(query.context)
48
+ return super if @skip_tracing || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
49
+ return super unless capture_field_timings?(query.context)
63
50
  trace_field(GraphQL::Metrics::INLINE_FIELD_TIMINGS, query) { super }
64
51
  end
65
52
 
66
53
  def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
67
- return super if skip_tracing?(query) || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
68
- return super unless GraphQL::Metrics.timings_capture_enabled?(query.context)
54
+ return super if @skip_tracing || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
55
+ return super unless capture_field_timings?(query.context)
69
56
  trace_field(GraphQL::Metrics::LAZY_FIELD_TIMINGS, query) { super }
70
57
  end
71
58
 
72
59
  private
73
60
 
74
- def skip_tracing?(query_or_multiplex)
75
- if !defined?(@skip_tracing)
76
- @skip_tracing = query_or_multiplex.context&.fetch(SKIP_GRAPHQL_METRICS_ANALYSIS, false)
61
+ def capture_field_timings?(context)
62
+ if !defined?(@capture_field_timings)
63
+ @capture_field_timings = !!context.namespace(CONTEXT_NAMESPACE)[TIMINGS_CAPTURE_ENABLED]
77
64
  end
78
65
 
79
- @skip_tracing
80
- end
81
-
82
- PreContext = Struct.new(
83
- :multiplex_start_time,
84
- :multiplex_start_time_monotonic,
85
- :parsing_start_time_offset,
86
- :parsing_duration,
87
- :lexing_start_time_offset,
88
- :lexing_duration
89
- ) do
90
- def reset
91
- self[:multiplex_start_time] = nil
92
- self[:multiplex_start_time_monotonic] = nil
93
- self[:parsing_start_time_offset] = nil
94
- self[:parsing_duration] = nil
95
- self[:lexing_start_time_offset] = nil
96
- self[:lexing_duration] = nil
97
- end
98
- end
99
-
100
- def pre_context
101
- # NOTE: This is used to store timings from lexing, parsing, validation, before we have a context to store
102
- # values in. Uses thread-safe Concurrent::ThreadLocalVar to store a set of values per thread.
103
- @pre_context ||= Concurrent::ThreadLocalVar.new(PreContext.new)
104
- @pre_context.value
105
- end
106
-
107
- def capture_multiplex_start_time
108
- pre_context.multiplex_start_time = GraphQL::Metrics.current_time
109
- pre_context.multiplex_start_time_monotonic = GraphQL::Metrics.current_time_monotonic
110
-
111
- yield
66
+ @capture_field_timings
112
67
  end
113
68
 
114
69
  def capture_lexing_time
115
- timed_result = GraphQL::Metrics.time { yield }
116
-
117
- pre_context.lexing_start_time_offset = timed_result.start_time
118
- pre_context.lexing_duration = timed_result.duration
119
-
120
- timed_result.result
70
+ result, duration = GraphQL::Metrics.time { yield }
71
+ @lexing_duration = duration
72
+ result
121
73
  end
122
74
 
123
75
  def capture_parsing_time
124
- timed_result = GraphQL::Metrics.time { yield }
125
-
126
- pre_context.parsing_start_time_offset = timed_result.start_time
127
- pre_context.parsing_duration = timed_result.duration
128
-
129
- timed_result.result
76
+ result, duration = GraphQL::Metrics.time { yield }
77
+ @parsing_duration = duration
78
+ result
130
79
  end
131
80
 
132
- # Also consolidates parsing timings (if any) from the `pre_context`
81
+ # Also consolidates parsing timings (if any)
133
82
  def capture_validation_time(context)
134
- # Queries may already be lexed and parsed before execution (whether a single query or multiplex).
135
- # If we don't have those values, use some sane defaults.
136
- if pre_context.lexing_duration.nil?
137
- pre_context.lexing_start_time_offset = pre_context.multiplex_start_time
138
- pre_context.lexing_duration = 0.0
139
- end
140
- if pre_context.parsing_duration.nil?
141
- pre_context.parsing_start_time_offset = pre_context.multiplex_start_time
142
- pre_context.parsing_duration = 0.0
143
- end
144
-
145
- timed_result = GraphQL::Metrics.time(pre_context.multiplex_start_time_monotonic) { yield }
83
+ result, duration = GraphQL::Metrics.time { yield }
146
84
 
147
85
  ns = context.namespace(CONTEXT_NAMESPACE)
86
+ ns[LEXING_DURATION] = @lexing_duration
87
+ ns[PARSING_DURATION] = @parsing_duration
88
+ ns[VALIDATION_DURATION] = duration
148
89
 
149
- ns[MULTIPLEX_START_TIME] = pre_context.multiplex_start_time
150
- ns[MULTIPLEX_START_TIME_MONOTONIC] = pre_context.multiplex_start_time_monotonic
151
- ns[LEXING_START_TIME_OFFSET] = pre_context.lexing_start_time_offset
152
- ns[LEXING_DURATION] = pre_context.lexing_duration
153
- ns[PARSING_START_TIME_OFFSET] = pre_context.parsing_start_time_offset
154
- ns[PARSING_DURATION] = pre_context.parsing_duration
155
- ns[VALIDATION_START_TIME_OFFSET] = timed_result.time_since_offset
156
- ns[VALIDATION_DURATION] = timed_result.duration
157
-
158
- timed_result.result
90
+ result
159
91
  end
160
92
 
161
93
  def capture_analysis_time(context)
162
94
  ns = context.namespace(CONTEXT_NAMESPACE)
163
95
 
164
- timed_result = GraphQL::Metrics.time(ns[MULTIPLEX_START_TIME_MONOTONIC]) { yield }
96
+ result, duration = GraphQL::Metrics.time { yield }
165
97
 
166
- ns[ANALYSIS_START_TIME_OFFSET] = timed_result.time_since_offset
167
- ns[ANALYSIS_DURATION] = timed_result.duration
98
+ ns[ANALYSIS_DURATION] = duration
168
99
 
169
- timed_result.result
100
+ result
170
101
  end
171
102
 
172
103
  def capture_query_start_time(context)
@@ -179,20 +110,13 @@ module GraphQL
179
110
 
180
111
  def trace_field(context_key, query)
181
112
  ns = query.context.namespace(CONTEXT_NAMESPACE)
182
- offset_time = ns[GraphQL::Metrics::QUERY_START_TIME_MONOTONIC]
183
- start_time = GraphQL::Metrics.current_time_monotonic
184
113
  path = query.context[:current_path]
185
114
 
186
- result = yield
187
-
188
- duration = GraphQL::Metrics.current_time_monotonic - start_time
189
- time_since_offset = start_time - offset_time if offset_time
115
+ result, duration = GraphQL::Metrics.time { yield }
190
116
 
191
117
  path_excluding_numeric_indicies = path.select { |p| p.is_a?(String) }
192
118
  ns[context_key][path_excluding_numeric_indicies] ||= []
193
- ns[context_key][path_excluding_numeric_indicies] << {
194
- start_time_offset: time_since_offset, duration: duration
195
- }
119
+ ns[context_key][path_excluding_numeric_indicies] << duration
196
120
 
197
121
  result
198
122
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module Metrics
5
- VERSION = "5.0.8"
5
+ VERSION = "6.0.1"
6
6
  end
7
7
  end
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "concurrent"
4
- require "graphql/metrics/version"
5
- require "graphql/metrics/instrumentation"
6
- require "graphql/metrics/trace"
7
- require "graphql/metrics/tracer"
8
- require "graphql/metrics/analyzer"
3
+ require_relative "metrics/version"
4
+ require_relative "metrics/instrumentation"
5
+ require_relative "metrics/trace"
6
+ require_relative "metrics/analyzer"
9
7
 
10
8
  module GraphQL
11
9
  module Metrics
@@ -27,22 +25,13 @@ module GraphQL
27
25
  MULTIPLEX_START_TIME_MONOTONIC = :multiplex_start_time_monotonic
28
26
  QUERY_START_TIME = :query_start_time
29
27
  QUERY_START_TIME_MONOTONIC = :query_start_time_monotonic
30
- LEXING_START_TIME_OFFSET = :lexing_start_time_offset
31
28
  LEXING_DURATION = :lexing_duration
32
- PARSING_START_TIME_OFFSET = :parsing_start_time_offset
33
29
  PARSING_DURATION = :parsing_duration
34
- VALIDATION_START_TIME_OFFSET = :validation_start_time_offset
35
30
  VALIDATION_DURATION = :validation_duration
36
- ANALYSIS_START_TIME_OFFSET = :analysis_start_time_offset
37
31
  ANALYSIS_DURATION = :analysis_duration
38
32
  INLINE_FIELD_TIMINGS = :inline_field_timings
39
33
  LAZY_FIELD_TIMINGS = :lazy_field_timings
40
34
 
41
- def self.timings_capture_enabled?(context)
42
- return false unless context
43
- !!context.namespace(CONTEXT_NAMESPACE)[TIMINGS_CAPTURE_ENABLED]
44
- end
45
-
46
35
  def self.current_time
47
36
  Process.clock_gettime(Process::CLOCK_REALTIME)
48
37
  end
@@ -51,40 +40,32 @@ module GraphQL
51
40
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
52
41
  end
53
42
 
54
- def self.time(offset_time = nil)
43
+ def self.time
55
44
  start_time = current_time_monotonic
56
45
  result = yield
57
46
  duration = current_time_monotonic - start_time
58
- time_since_offset = start_time - offset_time if offset_time
59
- TimedResult.new(start_time, duration, time_since_offset, result)
47
+ [result, duration]
60
48
  end
61
49
 
62
- class TimedResult
63
- # NOTE: `time_since_offset` is used to produce start times timed phases of execution (validation, field
64
- # resolution). These start times are relative to the executed operation's start time, which is captured at the
65
- # outset of document parsing.
66
- #
67
- # The times produced are intentionally similar to:
68
- # https://github.com/apollographql/apollo-tracing#response-format
69
- #
70
- # Taking a field resolver start offset example:
71
- #
72
- # < start offset >
73
- # |------------------|----------|--------->
74
- # OS (t=0) FS (t=1) FE (t=2)
75
- #
76
- # OS = Operation start time
77
- # FS = Field resolver start time
78
- # FE = Field resolver end time
79
- #
80
- attr_reader :result, :start_time, :duration, :time_since_offset
81
-
82
- def initialize(start_time, duration, time_since_offset, result)
83
- @start_time = start_time
84
- @duration = duration
85
- @time_since_offset = time_since_offset
86
- @result = result
50
+ def self.use(
51
+ schema_defn,
52
+ analyzer:,
53
+ tracer: GraphQL::Metrics::Trace,
54
+ capture_timings: nil,
55
+ capture_field_timings: nil,
56
+ trace_mode: :default
57
+ )
58
+ if capture_field_timings && !capture_timings
59
+ raise ArgumentError, "Cannot capture field timings without capturing query timings"
87
60
  end
61
+
62
+ capture_timings = true if capture_timings.nil?
63
+ capture_field_timings = true if capture_field_timings.nil?
64
+ capture_field_timings = false if !capture_timings
65
+
66
+ schema_defn.trace_with(GraphQL::Metrics::Instrumentation, capture_field_timings: capture_field_timings)
67
+ schema_defn.trace_with(tracer, mode: trace_mode) if capture_timings
68
+ schema_defn.query_analyzer(analyzer)
88
69
  end
89
70
  end
90
71
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.8
4
+ version: 6.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Butcher
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-12-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: graphql
@@ -16,56 +15,42 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 1.12.10
18
+ version: '2.3'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: 1.12.10
27
- - !ruby/object:Gem::Dependency
28
- name: concurrent-ruby
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.1.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 1.1.0
25
+ version: '2.3'
41
26
  - !ruby/object:Gem::Dependency
42
27
  name: rake
43
28
  requirement: !ruby/object:Gem::Requirement
44
29
  requirements:
45
30
  - - "~>"
46
31
  - !ruby/object:Gem::Version
47
- version: '10.0'
32
+ version: '13.2'
48
33
  type: :development
49
34
  prerelease: false
50
35
  version_requirements: !ruby/object:Gem::Requirement
51
36
  requirements:
52
37
  - - "~>"
53
38
  - !ruby/object:Gem::Version
54
- version: '10.0'
39
+ version: '13.2'
55
40
  - !ruby/object:Gem::Dependency
56
41
  name: minitest
57
42
  requirement: !ruby/object:Gem::Requirement
58
43
  requirements:
59
44
  - - "~>"
60
45
  - !ruby/object:Gem::Version
61
- version: '5.0'
46
+ version: '6.0'
62
47
  type: :development
63
48
  prerelease: false
64
49
  version_requirements: !ruby/object:Gem::Requirement
65
50
  requirements:
66
51
  - - "~>"
67
52
  - !ruby/object:Gem::Version
68
- version: '5.0'
53
+ version: '6.0'
69
54
  - !ruby/object:Gem::Dependency
70
55
  name: graphql-batch
71
56
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +65,6 @@ dependencies:
80
65
  - - ">="
81
66
  - !ruby/object:Gem::Version
82
67
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: activesupport
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 5.1.5
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 5.1.5
97
68
  - !ruby/object:Gem::Dependency
98
69
  name: pry
99
70
  requirement: !ruby/object:Gem::Requirement
@@ -201,7 +172,10 @@ executables: []
201
172
  extensions: []
202
173
  extra_rdoc_files: []
203
174
  files:
175
+ - ".github/dependabot.yml"
204
176
  - ".github/workflows/cla.yml"
177
+ - ".github/workflows/dependabot_auto_merge.yml"
178
+ - ".github/workflows/release.yml"
205
179
  - ".github/workflows/ruby.yml"
206
180
  - ".gitignore"
207
181
  - ".rubocop-http---shopify-github-io-ruby-style-guide-rubocop-yml"
@@ -210,28 +184,26 @@ files:
210
184
  - CHANGELOG.md
211
185
  - CODE_OF_CONDUCT.md
212
186
  - Gemfile
187
+ - Gemfile.lock
213
188
  - LICENSE.txt
214
189
  - README.md
215
190
  - RELEASING
216
191
  - Rakefile
217
192
  - bin/console
218
193
  - bin/setup
219
- - gemfiles/graphql_1.13.gemfile
220
- - gemfiles/graphql_2.0.gemfile
194
+ - gemfiles/graphql_2.3.gemfile
221
195
  - gemfiles/graphql_head.gemfile
222
196
  - graphql_metrics.gemspec
223
197
  - lib/graphql/metrics.rb
224
198
  - lib/graphql/metrics/analyzer.rb
225
199
  - lib/graphql/metrics/instrumentation.rb
226
200
  - lib/graphql/metrics/trace.rb
227
- - lib/graphql/metrics/tracer.rb
228
201
  - lib/graphql/metrics/version.rb
229
202
  homepage: https://github.com/Shopify/graphql-metrics
230
203
  licenses:
231
204
  - MIT
232
205
  metadata:
233
206
  allowed_push_host: https://rubygems.org
234
- post_install_message:
235
207
  rdoc_options: []
236
208
  require_paths:
237
209
  - lib
@@ -239,15 +211,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
239
211
  requirements:
240
212
  - - ">="
241
213
  - !ruby/object:Gem::Version
242
- version: '0'
214
+ version: '3.3'
243
215
  required_rubygems_version: !ruby/object:Gem::Requirement
244
216
  requirements:
245
217
  - - ">="
246
218
  - !ruby/object:Gem::Version
247
219
  version: '0'
248
220
  requirements: []
249
- rubygems_version: 3.4.22
250
- signing_key:
221
+ rubygems_version: 4.0.20
251
222
  specification_version: 4
252
223
  summary: GraphQL Metrics Extractor
253
224
  test_files: []
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- eval_gemfile("../Gemfile")
4
-
5
- gem("graphql", "~> 2.0")
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphQL
4
- module Metrics
5
- class Tracer
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, though old versions of the gem aren't always consistent about this (see
8
- # https://github.com/rmosolgo/graphql-ruby/issues/3393). Most of them can be run multiple times when
9
- # multiplexing multiple queries.
10
- GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY = 'execute_multiplex' # wraps everything below this line; only run once
11
- GRAPHQL_GEM_LEXING_KEY = 'lex' # may not trigger if the query is passed in pre-parsed
12
- GRAPHQL_GEM_PARSING_KEY = 'parse' # may not trigger if the query is passed in pre-parsed
13
- GRAPHQL_GEM_VALIDATION_KEY = 'validate'
14
- GRAPHQL_GEM_ANALYZE_MULTIPLEX_KEY = 'analyze_multiplex' # wraps all `analyze_query`s; only run once
15
- GRAPHQL_GEM_ANALYZE_QUERY_KEY = 'analyze_query'
16
- GRAPHQL_GEM_EXECUTE_QUERY_KEY = 'execute_query'
17
- GRAPHQL_GEM_TRACING_FIELD_KEYS = [
18
- GRAPHQL_GEM_TRACING_FIELD_KEY = 'execute_field',
19
- GRAPHQL_GEM_TRACING_LAZY_FIELD_KEY = 'execute_field_lazy'
20
- ]
21
-
22
- include GraphQL::Metrics::Trace
23
-
24
- def initialize
25
- # no-op, but don't want the behavior from GraphQL::Metrics::Trace
26
- end
27
-
28
- def trace(key, data, &block)
29
- # NOTE: Context doesn't exist yet during lexing, parsing.
30
- context = data[:query]&.context
31
- skip_tracing = context&.fetch(GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS, false)
32
- return yield if skip_tracing
33
-
34
- case key
35
- when GRAPHQL_GEM_EXECUTE_MULTIPLEX_KEY
36
- return capture_multiplex_start_time(&block)
37
- when GRAPHQL_GEM_LEXING_KEY
38
- return capture_lexing_time(&block)
39
- when GRAPHQL_GEM_PARSING_KEY
40
- return capture_parsing_time(&block)
41
- when GRAPHQL_GEM_VALIDATION_KEY
42
- return capture_validation_time(context, &block)
43
- when GRAPHQL_GEM_ANALYZE_MULTIPLEX_KEY
44
- # Ensures that we reset potentially long-lived PreContext objects between multiplexs. We reset at this point
45
- # since all parsing and validation will be done by this point, and a GraphQL::Query::Context will exist.
46
- pre_context.reset
47
- return yield
48
- when GRAPHQL_GEM_ANALYZE_QUERY_KEY
49
- return capture_analysis_time(context, &block)
50
- when GRAPHQL_GEM_EXECUTE_QUERY_KEY
51
- capture_query_start_time(context, &block)
52
- when *GRAPHQL_GEM_TRACING_FIELD_KEYS
53
- return yield if context[SKIP_FIELD_AND_ARGUMENT_METRICS]
54
- return yield unless GraphQL::Metrics.timings_capture_enabled?(data[:query].context)
55
-
56
- context_key = case key
57
- when GRAPHQL_GEM_TRACING_FIELD_KEY
58
- GraphQL::Metrics::INLINE_FIELD_TIMINGS
59
- when GRAPHQL_GEM_TRACING_LAZY_FIELD_KEY
60
- GraphQL::Metrics::LAZY_FIELD_TIMINGS
61
- end
62
-
63
- trace_field(context_key, data[:query], &block)
64
- else
65
- return yield
66
- end
67
- end
68
- end
69
- end
70
- end