sentry-ruby/lib/sentry/breadcrumb/sentry_logger.rb
# frozen_string_literal: true
require "logger"
module Sentry
class Breadcrumb
module SentryLogger
LEVELS = {
::Logger::DEBUG => "debug",
::Logger::INFO => "info",
::Logger::WARN => "warn",
::Logger::ERROR => "error",
::Logger::FATAL => "fatal"
}.freeze
def add(*args, &block)
super
add_breadcrumb(*args, &block)
nil
end
def add_breadcrumb(severity, message = nil, progname = nil)
# because the breadcrumbs now belongs to different Hub's Scope in different threads
# we need to make sure the current thread's Hub has been set before adding breadcrumbs
return unless Sentry.initialized? && Sentry.get_current_hub
category = "logger"
# this is because the nature of Ruby Logger class:
#
# when given 1 argument, the argument will become both message and progname
#
# ```
# logger.info("foo")
# # message == progname == "foo"
# ```
#
# and to specify progname with a different message,
# we need to pass the progname as the argument and pass the message as a proc
#
# ```
# logger.info("progname") { "the message" }
# ```
#
# so the condition below is to replicate the similar behavior
if message.nil?
if block_given?
message = yield
category = progname
else
message = progname
end
end
return if ignored_logger?(progname) || message == ""
# some loggers will add leading/trailing space as they (incorrectly, mind you)
# think of logging as a shortcut to std{out,err}
message = message.to_s.strip
last_crumb = current_breadcrumbs.peek
# try to avoid dupes from logger broadcasts
if last_crumb.nil? || last_crumb.message != message
level = Sentry::Breadcrumb::SentryLogger::LEVELS.fetch(severity, nil)
crumb = Sentry::Breadcrumb.new(
level: level,
category: category,
message: message,
type: severity >= 3 ? "error" : level
)
Sentry.add_breadcrumb(crumb, hint: { severity: severity })
end
end
private
def ignored_logger?(progname)
progname == LOGGER_PROGNAME ||
Sentry.configuration.exclude_loggers.include?(progname)
end
def current_breadcrumbs
Sentry.get_current_scope.breadcrumbs
end
end
end
end
::Logger.send(:prepend, Sentry::Breadcrumb::SentryLogger)