Skip to content

Commit 1e377d6

Browse files
authored
Tests for Rails.logger when :logger patch is enabled (#2659)
* [sentry-rails] add support for isolated specs * [sentry-rails] add tests for Rails logger when :logger patch is enabled
1 parent eeaeb2a commit 1e377d6

File tree

4 files changed

+233
-37
lines changed

4 files changed

+233
-37
lines changed

lib/sentry/test/rake_tasks.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# frozen_string_literal: true
2+
3+
require "rake/clean"
4+
require "rspec/core/rake_task"
5+
6+
module Sentry
7+
module Test
8+
module RakeTasks
9+
extend Rake::DSL
10+
11+
def self.define_spec_tasks(options = {})
12+
opts = {
13+
isolated_specs_pattern: "spec/isolated/**/*_spec.rb",
14+
spec_pattern: nil,
15+
spec_exclude_pattern: nil,
16+
spec_rspec_opts: nil,
17+
isolated_rspec_opts: nil
18+
}.merge(options)
19+
20+
RSpec::Core::RakeTask.new(:spec).tap do |task|
21+
task.pattern = opts[:spec_pattern] if opts[:spec_pattern]
22+
task.exclude_pattern = opts[:spec_exclude_pattern] if opts[:spec_exclude_pattern]
23+
task.rspec_opts = opts[:spec_rspec_opts] if opts[:spec_rspec_opts]
24+
end
25+
26+
namespace :spec do
27+
RSpec::Core::RakeTask.new(:isolated).tap do |task|
28+
task.pattern = opts[:isolated_specs_pattern]
29+
task.rspec_opts = opts[:isolated_rspec_opts] if opts[:isolated_rspec_opts]
30+
end
31+
end
32+
end
33+
34+
# Define versioned specs task (sentry-rails specific)
35+
def self.define_versioned_specs_task(options = {})
36+
opts = {
37+
rspec_opts: "--order rand"
38+
}.merge(options)
39+
40+
namespace :spec do
41+
RSpec::Core::RakeTask.new(:versioned).tap do |task|
42+
ruby_ver_dir = RUBY_VERSION.split(".")[0..1].join(".")
43+
matching_dir = Dir["spec/versioned/*"].detect { |dir| File.basename(dir) <= ruby_ver_dir }
44+
45+
unless matching_dir
46+
puts "No versioned specs found for ruby #{RUBY_VERSION}"
47+
exit 0
48+
end
49+
50+
puts "Running versioned specs from #{matching_dir} for ruby #{RUBY_VERSION}"
51+
52+
task.rspec_opts = opts[:rspec_opts]
53+
task.pattern = "#{matching_dir}/**/*_spec.rb"
54+
end
55+
end
56+
end
57+
end
58+
end
59+
end

sentry-rails/Rakefile

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,17 @@
11
# frozen_string_literal: true
22

33
require "bundler/gem_tasks"
4-
require "rspec/core/rake_task"
4+
require_relative "../lib/sentry/test/rake_tasks"
55

6-
RSpec::Core::RakeTask.new(:spec).tap do |task|
7-
task.rspec_opts = "--order rand"
8-
task.pattern = "spec/sentry/**/*_spec.rb"
9-
end
6+
Sentry::Test::RakeTasks.define_spec_tasks(
7+
spec_pattern: "spec/sentry/**/*_spec.rb",
8+
spec_rspec_opts: "--order rand --format progress",
9+
isolated_specs_pattern: "spec/isolated/**/*_spec.rb",
10+
isolated_rspec_opts: "--format progress"
11+
)
1012

11-
namespace :spec do
12-
RSpec::Core::RakeTask.new(:versioned).tap do |task|
13-
ruby_ver_dir = RUBY_VERSION.split(".")[0..1].join(".")
14-
matching_dir = Dir["spec/versioned/*"].detect { |dir| File.basename(dir) <= ruby_ver_dir }
13+
Sentry::Test::RakeTasks.define_versioned_specs_task(
14+
rspec_opts: "--order rand --format progress"
15+
)
1516

16-
unless matching_dir
17-
puts "No versioned specs found for ruby #{RUBY_VERSION}"
18-
exit 0
19-
end
20-
21-
puts "Running versioned specs from #{matching_dir} for ruby #{RUBY_VERSION}"
22-
23-
task.rspec_opts = "--order rand"
24-
task.pattern = "#{matching_dir}/**/*_spec.rb"
25-
end
26-
end
27-
28-
task :isolated_specs do
29-
Dir["spec/isolated/*"].each do |file|
30-
sh "bundle exec ruby #{file}"
31-
end
32-
end
33-
34-
task default: [:spec, :"spec:versioned", :isolated_specs]
17+
task default: [:spec, :"spec:versioned", :"spec:isolated"]
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# frozen_string_literal: true
2+
3+
begin
4+
require "simplecov"
5+
SimpleCov.command_name "RailsLoggerPatch"
6+
rescue LoadError
7+
end
8+
9+
require "logger"
10+
require "sentry-ruby"
11+
require "sentry/test_helper"
12+
13+
require_relative "../dummy/test_rails_app/app"
14+
15+
RSpec.describe "Rails.logger with :logger patch" do
16+
include Sentry::TestHelper
17+
18+
# Set up a real Rails app with logger
19+
let(:log_output) { StringIO.new }
20+
let(:app) do
21+
make_basic_app do |config|
22+
config.enable_logs = true
23+
config.enabled_patches = [:logger]
24+
config.max_log_events = 10
25+
config.sdk_logger = Logger.new(nil)
26+
end
27+
end
28+
29+
before do
30+
app
31+
Rails.logger = Logger.new(log_output)
32+
end
33+
34+
context "when :logger patch is enabled" do
35+
it "captures Rails.logger calls when :logger patch is enabled" do
36+
Rails.logger.debug("Test debug message")
37+
Rails.logger.info("Test info message")
38+
Rails.logger.warn("Test warning message")
39+
Rails.logger.error("Test error message")
40+
Rails.logger.fatal("Test fatal message")
41+
42+
Sentry.get_current_client.log_event_buffer.flush
43+
44+
expect(sentry_logs).not_to be_empty
45+
46+
log_messages = sentry_logs.map { |log| log[:body] }
47+
expect(log_messages).to include(
48+
"Test debug message",
49+
"Test info message",
50+
"Test warning message",
51+
"Test error message",
52+
"Test fatal message"
53+
)
54+
55+
test_logs = sentry_logs.select { |log| log[:body].start_with?("Test ") }
56+
log_levels = test_logs.map { |log| log[:level] }
57+
expect(log_levels).to contain_exactly("debug", "info", "warn", "error", "fatal")
58+
end
59+
60+
it "captures Rails.logger calls with block syntax" do
61+
Rails.logger.info { "Block message" }
62+
63+
Sentry.get_current_client.log_event_buffer.flush
64+
65+
expect(sentry_logs).not_to be_empty
66+
67+
log_messages = sentry_logs.map { |log| log[:body] }
68+
expect(log_messages).to include("Block message")
69+
70+
block_log = sentry_logs.find { |log| log[:body] == "Block message" }
71+
expect(block_log[:level]).to eq("info")
72+
end
73+
74+
it "captures Rails.logger calls with progname" do
75+
Rails.logger.info("MyProgram") { "Message with progname" }
76+
77+
Sentry.get_current_client.log_event_buffer.flush
78+
79+
expect(sentry_logs).not_to be_empty
80+
81+
log_messages = sentry_logs.map { |log| log[:body] }
82+
expect(log_messages).to include("Message with progname")
83+
84+
progname_log = sentry_logs.find { |log| log[:body] == "Message with progname" }
85+
expect(progname_log[:level]).to eq("info")
86+
end
87+
88+
it "does not capture Sentry SDK internal logs" do
89+
Rails.logger.info(Sentry::Logger::PROGNAME) { "Internal Sentry message" }
90+
91+
Sentry.get_current_client.log_event_buffer.flush
92+
93+
log_messages = sentry_logs.map { |log| log[:body] }
94+
expect(log_messages).not_to include("Internal Sentry message")
95+
end
96+
97+
it "strips whitespace from log messages" do
98+
Rails.logger.info(" Message with whitespace ")
99+
100+
Sentry.get_current_client.log_event_buffer.flush
101+
102+
expect(sentry_logs).not_to be_empty
103+
104+
log_messages = sentry_logs.map { |log| log[:body] }
105+
expect(log_messages).to include("Message with whitespace")
106+
end
107+
108+
it "handles non-string log messages" do
109+
Rails.logger.info(12345)
110+
111+
Sentry.get_current_client.log_event_buffer.flush
112+
113+
expect(sentry_logs).not_to be_empty
114+
115+
log_messages = sentry_logs.map { |log| log[:body] }
116+
expect(log_messages).to include("12345")
117+
end
118+
end
119+
120+
context "when Rails.logger is a BroadcastLogger", skip: !defined?(ActiveSupport::BroadcastLogger) do
121+
let(:string_io1) { StringIO.new }
122+
let(:string_io2) { StringIO.new }
123+
let(:logger1) { Logger.new(string_io1) }
124+
let(:logger2) { Logger.new(string_io2) }
125+
let(:broadcast_logger) { ActiveSupport::BroadcastLogger.new(logger1, logger2) }
126+
let(:broadcast_app) do
127+
make_basic_app do |config|
128+
config.enable_logs = true
129+
config.enabled_patches = [:logger]
130+
config.max_log_events = 10
131+
config.sdk_logger = Logger.new(nil)
132+
end
133+
end
134+
135+
before do
136+
broadcast_app
137+
Rails.logger = broadcast_logger
138+
end
139+
140+
it "captures logs from BroadcastLogger" do
141+
Rails.logger.info("Broadcast message")
142+
143+
Sentry.get_current_client.log_event_buffer.flush
144+
145+
expect(sentry_logs).not_to be_empty
146+
147+
log_messages = sentry_logs.map { |log| log[:body] }
148+
expect(log_messages).to include("Broadcast message")
149+
150+
broadcast_log = sentry_logs.find { |log| log[:body] == "Broadcast message" }
151+
expect(broadcast_log[:level]).to eq("info")
152+
153+
expect(string_io1.string).to include("Broadcast message")
154+
expect(string_io2.string).to include("Broadcast message")
155+
end
156+
end
157+
end

sentry-ruby/Rakefile

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@ CLOBBER.include "pkg"
66
require "bundler/gem_helper"
77
Bundler::GemHelper.install_tasks(name: "sentry-ruby")
88

9-
require "rspec/core/rake_task"
9+
require_relative "../lib/sentry/test/rake_tasks"
1010

1111
ISOLATED_SPECS = "spec/isolated/**/*_spec.rb"
1212

13-
RSpec::Core::RakeTask.new(:spec).tap do |task|
14-
task.exclude_pattern = ISOLATED_SPECS
15-
end
13+
Sentry::Test::RakeTasks.define_spec_tasks(
14+
isolated_specs_pattern: ISOLATED_SPECS,
15+
spec_exclude_pattern: ISOLATED_SPECS
16+
)
1617

17-
RSpec::Core::RakeTask.new(:isolated_specs).tap do |task|
18-
task.pattern = ISOLATED_SPECS
19-
end
20-
21-
task default: [:spec, :isolated_specs]
18+
task default: [:spec, :"spec:isolated"]

0 commit comments

Comments
 (0)