Skip to content

Commit 33bf51a

Browse files
SB-khushbumtwometrestevetgwizard
authored
Release/v6.30.0 (#857)
* remove copy buildkite command from dockerfile.ruby-maze-runner * add ruby4.0 to unit tests * Update CI, gemfile and logger spec for compatibility with all supported Ruby versions * remove trailing whitespaces * Use shell string for ruby 1.9.x to ensure compatibility * suggestion-add timeout,remove name params from method,change Gemfile to spec fixture for compatibility and changelog entry * update condition for modern bundler version support with simple approach * moved ostruct gem to test group and remove changelog entry as only updating unit tests/fixtures * Switch to ActiveSupport::Notifications.monotonic_subscribe * monotonic_subscribe was introduced in Rails 6.1+, add condition accordingly * change entry in CHANGELOG * Release v6.30.0 --------- Co-authored-by: Steve Kirkland <twometresteve@users.noreply.github.com> Co-authored-by: Adam Renberg Tamm <adam.renbergtamm@shopify.com>
1 parent 6f5c959 commit 33bf51a

11 files changed

Lines changed: 166 additions & 30 deletions

File tree

.github/workflows/test-package.yml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
fail-fast: false
1111
matrix:
12-
ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4']
12+
ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', '4.0']
1313
optional-groups: ['test sidekiq']
1414
include:
1515
- ruby-version: '1.9'
@@ -21,7 +21,12 @@ jobs:
2121
optional-groups: 'test'
2222
- ruby-version: 'jruby'
2323
optional-groups: 'test'
24-
24+
# Mark Ruby versions >= 3.4 as using modern bundler
25+
- ruby-version: '3.4'
26+
modern-bundler: true
27+
- ruby-version: '4.0'
28+
modern-bundler: true
29+
2530
steps:
2631
- uses: actions/checkout@v3
2732

@@ -30,8 +35,20 @@ jobs:
3035
with:
3136
ruby-version: ${{ matrix.ruby-version }}
3237

33-
- run: bundle install --with "${{ matrix.optional-groups }}" --binstubs
38+
# For Ruby 3.4+ (Bundler ≥ 2.4.0), use bundle config set with and bundle binstubs --all,
39+
# since the --with and --binstubs flags have been removed from modern Bundler versions
40+
- name: Install dependencies (Ruby >= 3.4)
41+
if: ${{ matrix.modern-bundler == true }}
42+
run: |
43+
bundle config set with "${{ matrix.optional-groups }}"
44+
bundle install
45+
bundle binstubs --all
3446
47+
# For Ruby < 3.4, use the legacy flags which are still supported
48+
- name: Install dependencies (Ruby < 3.4)
49+
if: ${{ matrix.modern-bundler != true }}
50+
run: bundle install --with "${{ matrix.optional-groups }}" --binstubs
51+
3552
- run: ./bin/rake spec
3653

3754
linting:

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
Changelog
22
=========
33

4+
## v6.30.0 (13 April 2026)
5+
6+
### Enhancements
7+
8+
* Use `ActiveSupport::Notifications.monotonic_subscribe` for performance improvement on compatible Rails versions
9+
| [#856](https://github.com/bugsnag/bugsnag-ruby/pull/856)
10+
411
## v6.29.0 (21 January 2026)
512

613
### Enhancements

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ group :test, optional: true do
2727
# WEBrick is no longer in the stdlib in Ruby 3.0
2828
gem 'webrick' if ruby_version >= Gem::Version.new('3.0.0')
2929

30+
# OpenStruct removed from default gems in Ruby 4.0+
31+
gem 'ostruct' if ruby_version >= Gem::Version.new('4.0')
32+
3033
gem 'rexml', '< 3.2.5' if ruby_version == Gem::Version.new('2.0.0')
3134

3235
if ruby_version >= Gem::Version.new('2.2.0') && ruby_version < Gem::Version.new('2.4.0')

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6.29.0
1+
6.30.0

dockerfiles/Dockerfile.ruby-maze-runner

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ COPY bugsnag.gemspec Gemfile VERSION ./
99
RUN bundle install
1010

1111
COPY CHANGELOG.md CONTRIBUTING.md TESTING.md LICENSE.txt Rakefile README.md UPGRADING.md .gitignore .rspec .rubocop.yml .rubocop_todo.yml .yardopts docker-compose.yml ./
12-
COPY .buildkite ./.buildkite
1312
COPY .git ./.git
1413
COPY .github ./.github
1514
COPY dockerfiles ./dockerfiles

lib/bugsnag/integrations/railtie.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class Railtie < ::Rails::Railtie
1515
# @api private
1616
# @param event [Hash] details of the event to subscribe to
1717
def event_subscription(event)
18-
ActiveSupport::Notifications.subscribe(event[:id]) do |*, event_id, data|
18+
# monotonic_subscribe was introduced in Rails 6.1+, check if it exists
19+
subscription_method = ActiveSupport::Notifications.respond_to?(:monotonic_subscribe) ? :monotonic_subscribe : :subscribe
20+
ActiveSupport::Notifications.send(subscription_method, event[:id]) do |*, event_id, data|
1921
filtered_data = data.slice(*event[:allowed_data])
2022
filtered_data[:event_name] = event[:id]
2123
filtered_data[:event_id] = event_id
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
source 'https://rubygems.org'
22

33
ruby_version = Gem::Version.new(RUBY_VERSION.dup)
4+
45
if ruby_version >= Gem::Version.new('3.4')
56
gem 'mutex_m', '0.3.0'
67
gem 'base64', '0.2.0'
7-
gem 'logger', '1.6.5'
8-
gem 'bigdecimal', '3.1.9'
8+
# Only use logger 1.6.5 for Ruby < 4.0, otherwise use >= 1.7 for compatibility with bugsnag
9+
if ruby_version < Gem::Version.new('4.0')
10+
gem 'logger', '1.6.5'
11+
gem 'bigdecimal', '3.1.9'
12+
else
13+
gem 'logger', '>= 1.7', '< 2.0'
14+
gem 'bigdecimal', '>= 4.0.0', '< 5.0.0'
15+
gem 'ostruct'
16+
gem 'benchmark'
17+
end
918
end
1019

1120
gem 'railties', ruby_version <= Gem::Version.new('2.6') ? '4.2.10' : '~> 6.0.2', require: %w(action_controller rails)
1221
gem 'rake', ruby_version <= Gem::Version.new('1.9.3') ? '~> 11.3.0' : '~> 12.3.0'
13-
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
22+
if ruby_version < Gem::Version.new('4.0')
23+
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
24+
end
1425
gem 'nokogiri', ruby_version < Gem::Version.new('2.6') ? '1.6.8' : '~> 1.13.9'
1526
gem 'bugsnag', path: '../../../..'

spec/fixtures/apps/rails-invalid-initializer-config/Gemfile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@ ruby_version = Gem::Version.new(RUBY_VERSION.dup)
55
if ruby_version >= Gem::Version.new('3.4')
66
gem 'mutex_m', '0.3.0'
77
gem 'base64', '0.2.0'
8-
gem 'logger', '1.6.5'
9-
gem 'bigdecimal', '3.1.9'
8+
# Only use logger 1.6.5 for Ruby < 4.0, otherwise use >= 1.7 for compatibility with bugsnag
9+
if ruby_version < Gem::Version.new('4.0')
10+
gem 'logger', '1.6.5'
11+
gem 'bigdecimal', '3.1.9'
12+
else
13+
gem 'logger', '>= 1.7', '< 2.0'
14+
gem 'bigdecimal', '>= 4.0.0', '< 5.0.0'
15+
gem 'ostruct'
16+
gem 'benchmark'
17+
end
1018
end
1119

1220
gem 'railties', ruby_version <= Gem::Version.new('2.6') ? '4.2.10' : '~> 6.0.2', require: %w(action_controller rails)
1321
gem 'rake', ruby_version <= Gem::Version.new('1.9.3') ? '~> 11.3.0' : '~> 12.3.0'
14-
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
22+
if ruby_version < Gem::Version.new('4.0')
23+
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
24+
end
1525
gem 'nokogiri', ruby_version < Gem::Version.new('2.6') ? '1.6.8' : '~> 1.13.9'
1626
gem 'bugsnag', path: '../../../..'

spec/fixtures/apps/rails-no-config/Gemfile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@ ruby_version = Gem::Version.new(RUBY_VERSION.dup)
55
if ruby_version >= Gem::Version.new('3.4')
66
gem 'mutex_m', '0.3.0'
77
gem 'base64', '0.2.0'
8-
gem 'logger', '1.6.5'
9-
gem 'bigdecimal', '3.1.9'
8+
# Only use logger 1.6.5 for Ruby < 4.0, otherwise use >= 1.7 for compatibility with bugsnag
9+
if ruby_version < Gem::Version.new('4.0')
10+
gem 'logger', '1.6.5'
11+
gem 'bigdecimal', '3.1.9'
12+
else
13+
gem 'logger', '>= 1.7', '< 2.0'
14+
gem 'bigdecimal', '>= 4.0.0', '< 5.0.0'
15+
gem 'ostruct'
16+
gem 'benchmark'
17+
end
1018
end
1119

1220
gem 'railties', ruby_version <= Gem::Version.new('2.6') ? '4.2.10' : '~> 6.0.2', require: %w(action_controller rails)
1321
gem 'rake', ruby_version <= Gem::Version.new('1.9.3') ? '~> 11.3.0' : '~> 12.3.0'
14-
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
22+
if ruby_version < Gem::Version.new('4.0')
23+
gem 'minitest', ruby_version <= Gem::Version.new('2.2') ? '5.11.3' : '~> 5.14.0'
24+
end
1525
gem 'nokogiri', ruby_version < Gem::Version.new('2.6') ? '1.6.8' : '~> 1.13.9'
1626
gem 'bugsnag', path: '../../../..'

spec/integrations/logger_spec.rb

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'spec_helper'
2+
require 'timeout'
23

34
describe 'Configuration.logger' do
45

@@ -19,23 +20,72 @@
1920
def run_app(name)
2021
out_reader, out_writer = IO.pipe
2122
Dir.chdir(File.join(File.dirname(__FILE__), "../fixtures/apps/#{name}")) do
22-
Bundler.with_clean_env do
23-
pid = Process.spawn('bundle install',
24-
out: out_writer.fileno,
25-
err: out_writer.fileno)
26-
Process.waitpid(pid, 0)
27-
pid = Process.spawn(@env, 'bundle exec rackup config.ru',
28-
out: out_writer.fileno,
29-
err: out_writer.fileno)
30-
sleep(2)
31-
Process.kill(1, pid)
23+
# Determine which Bundler env method to use based on availability
24+
# Ruby 4.0+ uses with_unbundled_env, Ruby 2-3.x uses with_clean_env, Ruby 1.9.2 has no env isolation
25+
if Bundler.respond_to?(:with_unbundled_env)
26+
Bundler.with_unbundled_env do
27+
execute_bundle_and_app(out_writer)
28+
end
29+
elsif Bundler.respond_to?(:with_clean_env)
30+
Bundler.with_clean_env do
31+
execute_bundle_and_app(out_writer)
32+
end
33+
else
34+
# Ruby 1.9.2: No env isolation available
35+
execute_bundle_and_app(out_writer)
3236
end
3337
end
3438
out_writer.close
3539
output = ""
3640
output << out_reader.gets until out_reader.eof?
3741
output
3842
end
43+
44+
private
45+
46+
def execute_bundle_and_app(out_writer)
47+
# Handle Bundler install for different Ruby versions
48+
ruby_version = Gem::Version.new(RUBY_VERSION.dup)
49+
50+
if ruby_version >= Gem::Version.new('3.4')
51+
# Ruby 3.4+: New Bundler syntax with separate steps
52+
pid = Process.spawn('bundle config set with "test"',
53+
out: out_writer.fileno,
54+
err: out_writer.fileno)
55+
Process.waitpid(pid, 0)
56+
pid = Process.spawn('bundle install',
57+
out: out_writer.fileno,
58+
err: out_writer.fileno)
59+
Process.waitpid(pid, 0)
60+
pid = Process.spawn('bundle binstubs --all',
61+
out: out_writer.fileno,
62+
err: out_writer.fileno)
63+
Process.waitpid(pid, 0)
64+
else
65+
# Ruby < 3.4: Legacy Bundler syntax (works for 1.9.2+)
66+
pid = Process.spawn('bundle install --with test --binstubs',
67+
out: out_writer.fileno,
68+
err: out_writer.fileno)
69+
Process.waitpid(pid, 0)
70+
end
71+
72+
# Run the Rails app
73+
pid = Process.spawn(@env, 'bundle exec rackup config.ru',
74+
out: out_writer.fileno,
75+
err: out_writer.fileno)
76+
sleep(2)
77+
Process.kill('TERM', pid)
78+
begin
79+
# Wait up to 5 seconds for the process to exit
80+
Timeout.timeout(5) { Process.waitpid(pid) }
81+
rescue Timeout::Error
82+
# If still running, force kill
83+
Process.kill('KILL', pid) rescue nil
84+
Process.waitpid(pid) rescue nil
85+
rescue Errno::ECHILD
86+
# Already exited
87+
end
88+
end
3989
context 'sets an API key using the BUGSNAG_API_KEY env var' do
4090
it 'does not log a warning' do
4191
skip "Incompatible with Ruby <2.0 and JRuby" if incompatible
@@ -81,19 +131,45 @@ def run_app(name)
81131

82132
context 'in a script' do
83133
key_warning = /\[Bugsnag\] .* No valid API key has been set, notifications will not be sent/
84-
134+
85135
def run_app(name)
86136
output = ''
87137
Dir.chdir(File.join(File.dirname(__FILE__), "../fixtures/apps/scripts")) do
88-
Bundler.with_clean_env do
89-
IO.popen([@env, 'bundle', 'exec', 'ruby', "#{name}.rb", err: [:child, :out]]) do |io|
90-
output << io.read
138+
# Determine which Bundler env method to use based on availability
139+
# Ruby 4.0+ uses with_unbundled_env, Ruby 2-3.x uses with_clean_env, Ruby 1.9.2 has no env isolation
140+
if Bundler.respond_to?(:with_unbundled_env)
141+
Bundler.with_unbundled_env do
142+
execute_script(name, output)
91143
end
144+
elsif Bundler.respond_to?(:with_clean_env)
145+
Bundler.with_clean_env do
146+
execute_script(name, output)
147+
end
148+
else
149+
# Ruby 1.9.2: No env isolation available
150+
execute_script(name, output)
92151
end
93152
end
94153
output
95154
end
96155

156+
private
157+
158+
def execute_script(name, output)
159+
if RUBY_VERSION < '2.0.0'
160+
# Ruby 1.9.x: Use shell string with environment variables
161+
env_str = @env.map { |k, v| "#{k}='#{v}'" }.join(' ')
162+
IO.popen("#{env_str} bundle exec ruby #{name}.rb 2>&1") do |io|
163+
output << io.read
164+
end
165+
else
166+
# Ruby 2.0+: Use array form with env hash and stderr redirection
167+
IO.popen([@env, 'bundle', 'exec', 'ruby', "#{name}.rb", err: [:child, :out]]) do |io|
168+
output << io.read
169+
end
170+
end
171+
end
172+
97173
context 'sets an API key using the BUGSNAG_API_KEY env var' do
98174
it 'does not log a warning' do
99175
@env['BUGSNAG_API_KEY'] = 'c34a2472bd240ac0ab0f52715bbdc05d'

0 commit comments

Comments
 (0)