From 2715c64e935751ca10c77524f1e510becf4ab7e5 Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Thu, 13 Aug 2026 17:10:07 +1200 Subject: [PATCH 1/2] Fix Rails main integration tests Two failures under Rails main (Ruby 4.0, SimpleCov 1.x): SimpleCov 1.0 replaced the `running` accessor with `active_session?` and deprecated `add_filter` in favor of `skip`, so the test app's test_helper crashed with NoMethodError before any test could load. Both call sites now pick the available API. Rails main assigns ActiveSupport::LogSubscriber.logger once during boot instead of falling back to Rails.logger on each event, so log subscribers such as Lograge kept writing to the boot logger after LogStruct replaced Rails.logger, and request logs bypassed the LogStruct appenders. The initializer order that decides this is not guaranteed, which is why it only reproduced on a freshly generated app. --- lib/log_struct/semantic_logger/setup.rb | 6 ++++++ rails_test_app/create_app.rb | 7 ++++++- .../integration/logging_integration_test.rb | 7 +++++++ rails_test_app/templates/test/test_helper.rb | 17 +++++++++++++++-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/log_struct/semantic_logger/setup.rb b/lib/log_struct/semantic_logger/setup.rb index 49e2eb0..17da83c 100644 --- a/lib/log_struct/semantic_logger/setup.rb +++ b/lib/log_struct/semantic_logger/setup.rb @@ -221,6 +221,12 @@ def self.replace_rails_logger(app) # Replace Rails.logger Rails.logger = logger + # Rails assigns ActiveSupport::LogSubscriber.logger once during boot + # (in the active_support.set_log_subscriber_logger initializer), so log + # subscribers such as Lograge keep writing to the original boot logger + # unless this reference is updated along with Rails.logger. + ActiveSupport::LogSubscriber.logger = logger + # Also replace various component loggers ActiveRecord::Base.logger = logger if defined?(ActiveRecord::Base) ActionController::Base.logger = logger if defined?(ActionController::Base) diff --git a/rails_test_app/create_app.rb b/rails_test_app/create_app.rb index 482e8cc..a695d55 100755 --- a/rails_test_app/create_app.rb +++ b/rails_test_app/create_app.rb @@ -356,7 +356,12 @@ def copy_template(file, target_path = nil) SimpleCov.start do root_path = File.expand_path('../../..', __dir__) coverage_dir File.join(root_path, 'coverage_rails') - add_filter '/rails_test_app/' + # SimpleCov >= 1.0 deprecated `add_filter` in favor of `skip` + if SimpleCov.respond_to?(:skip) + SimpleCov.skip '/rails_test_app/' + else + SimpleCov.add_filter '/rails_test_app/' + end enable_coverage :branch primary_coverage :branch end diff --git a/rails_test_app/templates/test/integration/logging_integration_test.rb b/rails_test_app/templates/test/integration/logging_integration_test.rb index 65f01f9..e72b071 100644 --- a/rails_test_app/templates/test/integration/logging_integration_test.rb +++ b/rails_test_app/templates/test/integration/logging_integration_test.rb @@ -4,6 +4,13 @@ require "test_helper" class LoggingIntegrationTest < ActionDispatch::IntegrationTest + # Rails assigns ActiveSupport::LogSubscriber.logger once during boot, so log + # subscribers (Lograge, Active Record, Action Controller) write to that + # reference rather than looking up Rails.logger on each event. + def test_log_subscribers_use_the_logstruct_logger + assert_kind_of LogStruct::SemanticLogger::Logger, ActiveSupport::LogSubscriber.logger + end + # Basic test to ensure the Rails app is working def test_healthcheck_works get "/health" diff --git a/rails_test_app/templates/test/test_helper.rb b/rails_test_app/templates/test/test_helper.rb index 0a32f2a..5776d96 100644 --- a/rails_test_app/templates/test/test_helper.rb +++ b/rails_test_app/templates/test/test_helper.rb @@ -7,7 +7,15 @@ require "open3" require "timeout" -unless SimpleCov.running +# SimpleCov >= 1.0 replaced the `running` accessor with `active_session?` +simplecov_started = + if SimpleCov.respond_to?(:active_session?) + SimpleCov.active_session? + else + SimpleCov.running + end + +unless simplecov_started SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::JSONFormatter @@ -19,7 +27,12 @@ gem_path = File.expand_path("../../../../", __FILE__) SimpleCov.root(gem_path) - add_filter "rails_test_app" + # SimpleCov >= 1.0 deprecated `add_filter` in favor of `skip` + if SimpleCov.respond_to?(:skip) + SimpleCov.skip "rails_test_app" + else + SimpleCov.add_filter "rails_test_app" + end coverage_dir "coverage_rails" From a5ded241da000e889aaa218378e5350da7ea7404 Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Thu, 13 Aug 2026 17:14:15 +1200 Subject: [PATCH 2/2] Bump CI Node version to 22 pnpm/action-setup installs the latest pnpm, which now requires Node >= 22.13, so every job that enabled the pnpm cache died with ERR_UNKNOWN_BUILTIN_MODULE on Node 20. GitHub also reports Node 20 as deprecated on its runners. --- .github/workflows/deploy-docs.yml | 4 ++-- .github/workflows/test.yml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 6a8ad9c..48ef63a 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -38,7 +38,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -48,7 +48,7 @@ jobs: - name: Enable pnpm cache uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'pnpm' cache-dependency-path: 'docs/pnpm-lock.yaml' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 25210c0..bcb6c6b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -34,7 +34,7 @@ jobs: - name: Enable pnpm cache uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: pnpm cache-dependency-path: | pnpm-lock.yaml @@ -107,7 +107,7 @@ jobs: - name: Setup Node.js (docs) uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -117,7 +117,7 @@ jobs: - name: Enable pnpm cache (docs) uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: pnpm cache-dependency-path: docs/pnpm-lock.yaml