Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions lib/bugsnag/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,10 @@ def initialize
# Set up logging
self.logger = Logger.new(STDOUT)
self.logger.level = Logger::INFO
self.logger.formatter = proc do |severity, datetime, progname, msg|
"** #{progname} #{datetime}: #{msg}\n"
self.logger.formatter = proc do |_severity, datetime, _progname, msg|
message = msg.to_s
message = message[PROG_NAME.length..-1].sub(/\A:?\s*/, "") if message.start_with?(PROG_NAME)
"** #{PROG_NAME} #{datetime}: #{message}\n"
end

# Configure the bugsnag middleware stack
Expand Down Expand Up @@ -440,31 +442,31 @@ def clear_request_data
#
# @param message [String, #to_s] The message to log
def info(message)
logger.info(PROG_NAME) { message }
logger.info(PROG_NAME) { format_log_message(message) }
end

##
# Logs a warning level message
#
# @param message [String, #to_s] The message to log
def warn(message)
logger.warn(PROG_NAME) { message }
logger.warn(PROG_NAME) { format_log_message(message) }
end

##
# Logs an error level message
#
# @param message [String, #to_s] The message to log
def error(message)
logger.error(PROG_NAME) { message }
logger.error(PROG_NAME) { format_log_message(message) }
end

##
# Logs a debug level message
#
# @param message [String, #to_s] The message to log
def debug(message)
logger.debug(PROG_NAME) { message }
logger.debug(PROG_NAME) { format_log_message(message) }
end

##
Expand Down Expand Up @@ -764,6 +766,14 @@ def auto_track_sessions=(track_sessions)

PROG_NAME = "[Bugsnag]"

def format_log_message(message)
message = message.to_s
return message if message.start_with?(PROG_NAME)
return PROG_NAME if message.empty?

"#{PROG_NAME} #{message}"
end

def default_hostname
# Send the heroku dyno name instead of hostname if available
ENV["DYNO"] || Socket.gethostname;
Expand Down
4 changes: 2 additions & 2 deletions spec/breadcrumbs/on_breadcrumb_callback_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ def call(breadcrumb)

message_index = 0
expected_messages = [
/^Error occurred in on_breadcrumb callback: 'Oh no!'$/,
/^on_breadcrumb callback stacktrace:/
/^\[Bugsnag\] Error occurred in on_breadcrumb callback: 'Oh no!'$/,
/^\[Bugsnag\] on_breadcrumb callback stacktrace:/
]

expect(logger).to have_received(:warn).with("[Bugsnag]").twice do |&block|
Expand Down
4 changes: 2 additions & 2 deletions spec/breadcrumbs/validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@

expect(breadcrumb.ignore?).to eq(true)

expect(Bugsnag.configuration.logger).to have_received(:debug) do |&block|
expect(block.call).to eq("Automatic breadcrumb of type #{type} ignored: #{name}")
expect(Bugsnag.configuration.logger).to have_received(:debug).with("[Bugsnag]") do |&block|
expect(block.call).to eq("[Bugsnag] Automatic breadcrumb of type #{type} ignored: #{name}")
end
end

Expand Down
12 changes: 6 additions & 6 deletions spec/bugsnag_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@
end

expected_messages = [
/^Error in notify block: This is the error message$/,
/^Error in notify block stacktrace: \[/
/^\[Bugsnag\] Error in notify block: This is the error message$/,
/^\[Bugsnag\] Error in notify block stacktrace: \[/
].each

expect(Bugsnag.configuration.logger).to have_received(:warn).with('[Bugsnag]').twice do |&block|
expect(Bugsnag.configuration.logger).to have_received(:warn).with("[Bugsnag]").twice do |&block|
expect(block.call).to match(expected_messages.next)
end

Expand All @@ -84,11 +84,11 @@
end

expected_messages = [
/^Error in internal notify block: This is an auto_notify error$/,
/^Error in internal notify block stacktrace: \[/
/^\[Bugsnag\] Error in internal notify block: This is an auto_notify error$/,
/^\[Bugsnag\] Error in internal notify block stacktrace: \[/
].each

expect(Bugsnag.configuration.logger).to have_received(:warn).with('[Bugsnag]').twice do |&block|
expect(Bugsnag.configuration.logger).to have_received(:warn).with("[Bugsnag]").twice do |&block|
expect(block.call).to match(expected_messages.next)
end

Expand Down
66 changes: 57 additions & 9 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
describe "logger" do
before do
@output = StringIO.new
@formatter = proc do |severity, _datetime, progname, message|
"#{progname} #{severity}: #{message}"
@formatter = proc do |severity, _datetime, _progname, message|
"#{severity}: #{message}"
end

logger = Logger.new(@output)
Expand All @@ -379,6 +379,47 @@ def output_lines
@output.readlines.map(&:chomp) # old rubies don't support `readlines(chomp: true)`
end

it "preserves the default log format" do
datetime = Time.utc(2026, 9, 6)
output = subject.logger.formatter.call(
"INFO", datetime, nil, "[Bugsnag] Info message"
)

expect(output).to eq("** [Bugsnag] #{datetime}: Info message\n")
expect(subject.logger.formatter.call("INFO", datetime, nil, "[Bugsnag]: Info message")).to eq(
"** [Bugsnag] #{datetime}: Info message\n"
)
expect(subject.logger.formatter.call("INFO", datetime, nil, "[Bugsnag]")).to eq(
"** [Bugsnag] #{datetime}: \n"
)
end

it "sets the Bugsnag progname on the logger as well as the message" do
logger = double("logger")
subject.logger = logger

%i[info warn error debug].each do |level|
expect(logger).to receive(level).with("[Bugsnag]") do |_progname, &block|
expect(block.call).to eq("[Bugsnag] #{level} message")
end

subject.public_send(level, "#{level} message")
end
end

it "does not leave a trailing space when the message is empty" do
logger = double("logger")
subject.logger = logger

[nil, ""].each do |message|
expect(logger).to receive(:info).with("[Bugsnag]") do |_progname, &block|
expect(block.call).to eq("[Bugsnag]")
end

subject.info(message)
end
end

context "using configure" do
before do
Bugsnag.configuration.api_key = nil
Expand All @@ -398,7 +439,7 @@ def output_lines

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq(
'[Bugsnag] WARN: No valid API key has been set, notifications will not be sent'
'WARN: [Bugsnag] No valid API key has been set, notifications will not be sent'
)
end

Expand All @@ -407,7 +448,7 @@ def output_lines

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq(
'[Bugsnag] WARN: No valid API key has been set, notifications will not be sent'
'WARN: [Bugsnag] No valid API key has been set, notifications will not be sent'
)
end
end
Expand All @@ -428,7 +469,7 @@ def output_lines

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq(
'[Bugsnag] WARN: No valid API key has been set, notifications will not be sent'
'WARN: [Bugsnag] No valid API key has been set, notifications will not be sent'
)
end

Expand Down Expand Up @@ -457,7 +498,7 @@ def output_lines
Bugsnag.configuration.info("Info message")

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq('[Bugsnag] INFO: Info message')
expect(output_lines.first).to eq('INFO: [Bugsnag] Info message')
end

it "should log warning messages to the set logger" do
Expand All @@ -466,7 +507,7 @@ def output_lines
Bugsnag.configuration.warn("Warning message")

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq('[Bugsnag] WARN: Warning message')
expect(output_lines.first).to eq('WARN: [Bugsnag] Warning message')
end

it "should log error messages to the set logger" do
Expand All @@ -475,7 +516,7 @@ def output_lines
Bugsnag.configuration.error("Error message")

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq('[Bugsnag] ERROR: Error message')
expect(output_lines.first).to eq('ERROR: [Bugsnag] Error message')
end

it "should log debug messages to the set logger" do
Expand All @@ -484,7 +525,14 @@ def output_lines
Bugsnag.configuration.debug("Debug message")

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq('[Bugsnag] DEBUG: Debug message')
expect(output_lines.first).to eq('DEBUG: [Bugsnag] Debug message')
end

it "does not duplicate an existing Bugsnag prefix" do
Bugsnag.configuration.info("[Bugsnag] Info message")

expect(output_lines.length).to be(1)
expect(output_lines.first).to eq('INFO: [Bugsnag] Info message')
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/integrations/logger_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
end

context 'in a Rails app' do
key_warning = '[Bugsnag]: No valid API key has been set, notifications will not be sent'
key_warning = '[Bugsnag] No valid API key has been set, notifications will not be sent'
is_jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
incompatible = (RUBY_VERSION < '2.0.0') || is_jruby

Expand Down
6 changes: 3 additions & 3 deletions spec/on_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
expect(called_count).to be(2)

expect(logger).to have_received(:debug).with("[Bugsnag]") do |&block|
expect(block.call).to eq("Not notifying RuntimeError due to ignore being signified in user provided middleware")
expect(block.call).to eq("[Bugsnag] Not notifying RuntimeError due to ignore being signified in user provided middleware")
end
end

Expand Down Expand Up @@ -257,8 +257,8 @@

message_index = 0
expected_messages = [
/^Error occurred in on_error callback: 'bad things'$/,
/^on_error callback stacktrace:/
/^\[Bugsnag\] Error occurred in on_error callback: 'bad things'$/,
/^\[Bugsnag\] on_error callback stacktrace:/
]

expect(logger).to have_received(:warn).with("[Bugsnag]").twice do |&block|
Expand Down
15 changes: 15 additions & 0 deletions spec/session_tracker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@
expect(payload["sessionCounts"].size).to eq(1)
end

it 'attributes invalid API key delivery failures to Bugsnag' do
output = StringIO.new
logger = Logger.new(output)
logger.formatter = proc do |_severity, _datetime, _progname, message|
message
end
Bugsnag.configuration.logger = logger
allow(Bugsnag.configuration).to receive(:valid_api_key?).and_return(false)

Bugsnag.start_session
Bugsnag.session_tracker.send_sessions

expect(output.string).to eq('[Bugsnag] Not delivering sessions due to an invalid api_key')
end

it 'sets details from config' do
Bugsnag.configure do |conf|
conf.auto_capture_sessions = true
Expand Down