gvl_metrics_middleware 0.2.1 → 0.3.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: 81e9afea6ad5c3271fb91da6b0f69efcd3e1f49153b7e5a278483701295ebbac
4
- data.tar.gz: 22363d1d03ee82e7a5e6475226fdf73414d9b643728dd0da6c4b7f05b86c6b29
3
+ metadata.gz: e9c303f29cd3924fceeeaa769037e69857a90f5b237c0ec10d5f94a412f5c03c
4
+ data.tar.gz: 52c7a388c144debe25968379af1769d1f406214fe634961727589ca98784b78d
5
5
  SHA512:
6
- metadata.gz: 4ba04171e7a5a1ae4eb7da1f9cbb32302d79e07679d05edc12f9d6dcc100bce0f514002368e94440f9b6cd00c313372d35b22accfda0905dae16083a29e26341
7
- data.tar.gz: cdcf224fafb3879e806e8a033c5622431baf77c14fda3b76baef184f4e8cf60862ce41838527b31ebc831124349d6b4995da1248114d8af483e8a19027688fef
6
+ metadata.gz: e83517c9c027b5329dcea41f6d051c1a2e5c685162a3057ee6c00294032289eb61aa8f444d4657284c9f6519d4e29458dcebd456f29018bd386a26b1cc4a9048
7
+ data.tar.gz: 4a992b0675b6f32161d796f142e47c2b9232eb647bbbd7e0a64d324577794be882b5d7131dbaa24adbc74517c17dd9c3a95abaa1a6a642c5c68ec6c6ee5dd06d
data/Appraisals CHANGED
@@ -31,3 +31,31 @@ appraise "rails_71" do
31
31
  gem "railties", "~> 7.1.0"
32
32
  gem "activesupport", "~> 7.1.0"
33
33
  end
34
+
35
+ appraise "sidekiq_52" do
36
+ gem "sidekiq", "~> 5.2"
37
+ gem "rails", "~> 7.1.0"
38
+ gem "railties", "~> 7.1.0"
39
+ gem "activesupport", "~> 7.1.0"
40
+ end
41
+
42
+ appraise "sidekiq_6x" do
43
+ gem "sidekiq", "~> 6.5", ">= 6.5.12"
44
+ gem "rails", "~> 7.1.0"
45
+ gem "railties", "~> 7.1.0"
46
+ gem "activesupport", "~> 7.1.0"
47
+ end
48
+
49
+ appraise "sidekiq_7x" do
50
+ gem "sidekiq", "~> 7.3"
51
+ gem "rails", "~> 8.0.0"
52
+ gem "railties", "~> 8.0.0"
53
+ gem "activesupport", "~> 8.0.0"
54
+ end
55
+
56
+ appraise "sidekiq_8x" do
57
+ gem "sidekiq", "~> 8.1"
58
+ gem "rails", "~> 8.0.0"
59
+ gem "railties", "~> 8.0.0"
60
+ gem "activesupport", "~> 8.0.0"
61
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2026-01-26
4
+
5
+ - Add Ruby 4.0 support ([#25](https://github.com/speedshop/gvl_metrics_middleware/pull/25))
6
+ - Add support for Sidekiq 5.2 ([#23](https://github.com/speedshop/gvl_metrics_middleware/pull/23))
7
+ - Skip GVL measurement when no reporter is configured, improving performance ([#20](https://github.com/speedshop/gvl_metrics_middleware/pull/20))
8
+
3
9
  ## [0.2.1] - 2025-11-14
4
10
 
5
11
  - Fixed errors when middleware stack may have been modified ([#18](https://github.com/speedshop/gvl_metrics_middleware/pull/18))
data/README.md CHANGED
@@ -1,13 +1,10 @@
1
1
  # GVL Metrics Middleware
2
2
 
3
- `gvl_metrics_middleware` is a Ruby gem that provides middleware for monitoring and gathering metrics on Global VM Lock (
4
- GVL) in multi-threaded Ruby applications. This gem leverages
5
- [the `gvl_timing` gem](https://github.com/jhawthorn/gvl_timing) to measure time spent in the GVL and invokes a provided
6
- callback with the collected metrics data.
3
+ `gvl_metrics_middleware` is a Ruby gem that monitors the Global VM Lock (GVL) in multi-threaded Ruby applications. This gem uses [the `gvl_timing` gem](https://github.com/jhawthorn/gvl_timing) to measure time spent in the GVL. It then calls your callback with the metrics.
7
4
 
8
5
  ## Installation
9
6
 
10
- Add the gem to your applications Gemfile, and run `bundle install` to install the gem:
7
+ Add the gem to your application's Gemfile, and run `bundle install` to install the gem:
11
8
 
12
9
  ```bash
13
10
  gem 'gvl_metrics_middleware', git: "https://github.com/speedshop/gvl_metrics_middleware.git"
@@ -15,9 +12,7 @@ gem 'gvl_metrics_middleware', git: "https://github.com/speedshop/gvl_metrics_mid
15
12
 
16
13
  ## Usage
17
14
 
18
- The `gvl_metrics_middleware` automatically inserts the necessary middleware into your applications stack. To get
19
- started, configure a callback to handle the GVL metrics. Place the following configuration in your
20
- application’s `config/initializers`directory:
15
+ The `gvl_metrics_middleware` automatically adds itself to your application. To get started, set up a callback to handle the GVL metrics. Put this code in your application's `config/initializers` folder:
21
16
 
22
17
  ```ruby
23
18
  # config/initializers/gvl_metrics_middleware.rb
@@ -35,7 +30,7 @@ GvlMetricsMiddleware.configure do |config|
35
30
  end
36
31
  ```
37
32
 
38
- For example, if you would like to record the GVL metrics in New Relic, you can use the following configuration.
33
+ For example, here is how to record the GVL metrics in New Relic.
39
34
 
40
35
  ```ruby
41
36
  # config/initializers/gvl_metrics_middleware.rb
@@ -67,28 +62,22 @@ GvlMetricsMiddleware.configure do |config|
67
62
  end
68
63
  ```
69
64
 
70
- After configuring, you should be able to set up custom charts in New Relic to visualize the GVL metrics. Here is an
71
- example chart:
65
+ After you set this up, you can create custom charts in New Relic to see the GVL metrics. Here is an example chart:
72
66
 
73
67
  ![Screenshot of the GVL metrics chart on New Relic](gvl-metrics.png)
74
68
 
75
69
  ## Available Metrics
76
70
 
77
- The `gvl_metrics_middleware` reports the following metrics. The metrics are all reported in nanoseconds.
71
+ The `gvl_metrics_middleware` reports these metrics. All metrics are in nanoseconds.
78
72
 
79
- - **`total`**: The total duration of the request processing time, which is the sum of `running`, `io_wait`,
80
- and `gvl_wait`. This corresponds to the returned value from the value returned by the `GVLTiming::Timer#duration`
81
- method in `gvl_timing`.
82
- - **`running`**: The time a thread held the GVL and performed work (a.k.a CPU time). This corresponds to the
83
- value returned by the `GVLTiming::Timer#cpu_duration` method.
84
- - **`io_wait`**: The time spent waiting for I/O operations after releasing the GVL. This corresponds to the
85
- value returned by the `GVLTiming::Timer#idle_duration` method.
86
- - **`gvl_wait`**: The time spent waiting to acquire the GVL. This corresponds to the value returned by
87
- the `GVLTiming::Timer#stalled_duration` method.
73
+ - **`total`**: The total time to process the request. This equals `running` + `io_wait` + `gvl_wait`. Comes from `GVLTiming::Timer#duration` in `gvl_timing`.
74
+ - **`running`**: The time a thread held the GVL and did work. Also called CPU time. Comes from `GVLTiming::Timer#cpu_duration`.
75
+ - **`io_wait`**: The time spent waiting for I/O after the thread released the GVL. Comes from `GVLTiming::Timer#idle_duration`.
76
+ - **`gvl_wait`**: The time spent waiting to get the GVL. Comes from `GVLTiming::Timer#stalled_duration`.
88
77
 
89
78
  ## Sampling
90
79
 
91
- By default, the middleware samples 1% of requests and jobs to minimize overhead. You can adjust this sampling rate:
80
+ By default, the middleware samples 1% of requests and jobs to keep overhead low. You can change this rate:
92
81
  ```ruby
93
82
  GvlMetricsMiddleware.configure do |config|
94
83
  # Sample 25% of requests/jobs
@@ -98,46 +87,32 @@ GvlMetricsMiddleware.configure do |config|
98
87
  end
99
88
  ```
100
89
 
101
- The `sampling_rate` option accepts a value between `0.0` (no sampling) and `1.0` (100% sampling). The default is `0.01` (1%).
90
+ The `sampling_rate` option takes a value between `0.0` (no sampling) and `1.0` (100% sampling). The default is `0.01` (1%).
102
91
 
103
- The middleware will randomly decide whether to instrument each request or job based on the configured rate. The default 1% sampling provides meaningful metrics while maintaining minimal performance overhead.
92
+ The middleware will randomly pick which requests or jobs to measure based on this rate. The default 1% sampling gives you useful metrics while keeping overhead low.
104
93
 
105
- **Important**: Your metrics will only represent the sampled portion of traffic. You may need to adjust your alerting and analysis accordingly.
94
+ **Important**: Your metrics only show the sampled part of your traffic. You may need to adjust your alerts and analysis to match.
106
95
 
107
96
  ## Performance Overhead
108
97
 
109
- The overhead introduced by `gvl_metrics_middleware` is minimal. Benchmarking has shown only a 1% difference in response
110
- times between scenarios with and without GVL metrics collection. This result has been validated through an A/A test,
111
- where both the control and experiment groups ran identical code, and the difference remained at 1%. This 1% overhead is
112
- consistent with those reported in [Shopify's `gvltools`](https://github.com/Shopify/gvltools?tab=readme-ov-file#usage),
113
- where the overhead was measured at 1-5% in a production environment.
98
+ The overhead from `gvl_metrics_middleware` is small. Tests show only a 1% difference in response times. We ran tests with and without GVL metrics. We checked this with an A/A test. Both groups ran the same code. The difference stayed at 1%. This matches what [Shopify's `gvltools`](https://github.com/Shopify/gvltools?tab=readme-ov-file#usage) found. Their overhead was 1-5% in production.
114
99
 
115
- As stated in [the README of `gvltools`](https://github.com/Shopify/gvltools?tab=readme-ov-file#usage), the exact
116
- overhead is not yet known. However, unless you observe an immediate, significant jump in response times after
117
- deployment, the overhead is negligible and should not impact application performance. This makes the middleware a
118
- reliable choice for tracking GVL metrics in production environments.
100
+ As [the README of `gvltools`](https://github.com/Shopify/gvltools?tab=readme-ov-file#usage) says, the exact overhead is not known yet. But if you don't see a big jump in response times after you deploy, the overhead is small. It will not hurt your app's speed. This makes the middleware good for tracking GVL metrics in production.
119
101
 
120
102
  ## Development
121
103
 
122
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
123
- also run `bin/console` for an interactive prompt that will allow you to experiment.
104
+ After you check out the repo, run `bin/setup` to install what you need. Then run `rake test` to run the tests. You can also run `bin/console`. This gives you an interactive prompt where you can try things out.
124
105
 
125
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
126
- version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
127
- push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
106
+ To install this gem on your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`. Then run `bundle exec rake release`. This will create a git tag for the version. It will push git commits and the tag. It will also push the `.gem` file to [rubygems.org](https://rubygems.org).
128
107
 
129
108
  ## Contributing
130
109
 
131
- Bug reports and pull requests are welcome on GitHub at https://github.com/speedshop/gvl_metrics_middleware. This
132
- project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
133
- the [code of conduct](https://github.com/speedshop/gvl_metrics_middleware/blob/main/CODE_OF_CONDUCT.md).
110
+ Bug reports and pull requests are welcome on GitHub at https://github.com/speedshop/gvl_metrics_middleware. This project should be a safe, welcoming place for everyone. All contributors must follow the [code of conduct](https://github.com/speedshop/gvl_metrics_middleware/blob/main/CODE_OF_CONDUCT.md).
134
111
 
135
112
  ## License
136
113
 
137
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
114
+ This gem is open source under the [MIT License](https://opensource.org/licenses/MIT).
138
115
 
139
116
  ## Code of Conduct
140
117
 
141
- Everyone interacting in the GvlMetricsMiddleware project's codebases, issue trackers, chat rooms and mailing lists is
142
- expected to follow
143
- the [code of conduct](https://github.com/speedshop/gvl_metrics_middleware/blob/main/CODE_OF_CONDUCT.md).
118
+ Everyone who uses the GvlMetricsMiddleware project must follow the [code of conduct](https://github.com/speedshop/gvl_metrics_middleware/blob/main/CODE_OF_CONDUCT.md). This includes codebases, issue trackers, chat rooms, and mailing lists.
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 5.16"
6
+ gem "rake", "~> 13.0"
7
+ gem "rubocop", require: false
8
+ gem "rack-attack", "~> 6.8"
9
+ gem "sidekiq", "~> 5.2"
10
+ gem "rails", "~> 7.1.0"
11
+ gem "railties", "~> 7.1.0"
12
+ gem "activesupport", "~> 7.1.0"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 5.16"
6
+ gem "rake", "~> 13.0"
7
+ gem "rubocop", require: false
8
+ gem "rack-attack", "~> 6.8"
9
+ gem "sidekiq", "~> 6.5", ">= 6.5.12"
10
+ gem "rails", "~> 7.1.0"
11
+ gem "railties", "~> 7.1.0"
12
+ gem "activesupport", "~> 7.1.0"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 5.16"
6
+ gem "rake", "~> 13.0"
7
+ gem "rubocop", require: false
8
+ gem "rack-attack", "~> 6.8"
9
+ gem "sidekiq", "~> 7.3"
10
+ gem "rails", "~> 8.0.0"
11
+ gem "railties", "~> 8.0.0"
12
+ gem "activesupport", "~> 8.0.0"
13
+
14
+ gemspec path: "../"
@@ -0,0 +1,14 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 5.16"
6
+ gem "rake", "~> 13.0"
7
+ gem "rubocop", require: false
8
+ gem "rack-attack", "~> 6.8"
9
+ gem "sidekiq", "~> 8.1"
10
+ gem "rails", "~> 8.0.0"
11
+ gem "railties", "~> 8.0.0"
12
+ gem "activesupport", "~> 8.0.0"
13
+
14
+ gemspec path: "../"
@@ -19,7 +19,8 @@ module GvlMetricsMiddleware
19
19
  end
20
20
 
21
21
  def call(env)
22
- return @app.call(env) unless GvlMetricsMiddleware.should_sample?
22
+ reporter = self.class.reporter
23
+ return @app.call(env) if reporter.nil? || !GvlMetricsMiddleware.should_sample?
23
24
 
24
25
  response = nil
25
26
 
@@ -28,7 +29,7 @@ module GvlMetricsMiddleware
28
29
  end
29
30
 
30
31
  begin
31
- self.class.reporter&.call(gvl_times.duration_ns, gvl_times.running_duration_ns, gvl_times.idle_duration_ns, gvl_times.stalled_duration_ns)
32
+ reporter.call(gvl_times.duration_ns, gvl_times.running_duration_ns, gvl_times.idle_duration_ns, gvl_times.stalled_duration_ns)
32
33
  rescue => exception
33
34
  GvlMetricsMiddleware.on_report_failure&.call("Rack", exception)
34
35
 
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "gvl_timing"
4
- require "sidekiq/middleware/modules"
4
+
5
+ if ::Sidekiq::VERSION >= "6.5.0"
6
+ require "sidekiq/middleware/modules"
7
+ end
5
8
 
6
9
  module GvlMetricsMiddleware
7
10
  class Sidekiq
@@ -15,15 +18,18 @@ module GvlMetricsMiddleware
15
18
  end
16
19
  end
17
20
 
18
- include ::Sidekiq::ServerMiddleware
21
+ if ::Sidekiq::VERSION >= "6.5.0"
22
+ include ::Sidekiq::ServerMiddleware
23
+ end
19
24
 
20
25
  def call(job_instance, _job_payload, queue)
21
- return yield unless GvlMetricsMiddleware.should_sample?
26
+ reporter = self.class.reporter
27
+ return yield if reporter.nil? || !GvlMetricsMiddleware.should_sample?
22
28
 
23
29
  gvl_times = GVLTiming.measure { yield }
24
30
 
25
31
  begin
26
- self.class.reporter&.call(gvl_times.duration_ns, gvl_times.running_duration_ns, gvl_times.idle_duration_ns, gvl_times.stalled_duration_ns, job_class: job_instance.class.to_s, queue: queue)
32
+ reporter.call(gvl_times.duration_ns, gvl_times.running_duration_ns, gvl_times.idle_duration_ns, gvl_times.stalled_duration_ns, job_class: job_instance.class.to_s, queue: queue)
27
33
  rescue => exception
28
34
  GvlMetricsMiddleware.on_report_failure&.call("Sidekiq", exception)
29
35
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GvlMetricsMiddleware
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gvl_metrics_middleware
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Berkopec
@@ -86,6 +86,10 @@ files:
86
86
  - gemfiles/rails_80.gemfile
87
87
  - gemfiles/rails_81.gemfile
88
88
  - gemfiles/rails_edge.gemfile
89
+ - gemfiles/sidekiq_52.gemfile
90
+ - gemfiles/sidekiq_6x.gemfile
91
+ - gemfiles/sidekiq_7x.gemfile
92
+ - gemfiles/sidekiq_8x.gemfile
89
93
  - gvl-metrics.png
90
94
  - lib/gvl_metrics_middleware.rb
91
95
  - lib/gvl_metrics_middleware/rack.rb
@@ -115,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
119
  - !ruby/object:Gem::Version
116
120
  version: '0'
117
121
  requirements: []
118
- rubygems_version: 3.6.9
122
+ rubygems_version: 4.0.3
119
123
  specification_version: 4
120
124
  summary: Rack and Sidekiq middlewares for GVL metrics
121
125
  test_files: []