module Bugsnag
rubocop:todo Metrics/ModuleLength
Constants
Public Class Methods
Source
# File lib/bugsnag.rb, line 423 def add_metadata(section, key_or_data, *args) configuration.add_metadata(section, key_or_data, *args) end
Add values to metadata
@overload add_metadata
(section, data)
Merges data into the given section of metadata @param section [String, Symbol] @param data [Hash]
@overload add_metadata
(section, key, value)
Sets key to value in the given section of metadata. If the value is nil the key will be deleted @param section [String, Symbol] @param key [String, Symbol] @param value
@return [void]
Source
# File lib/bugsnag.rb, line 332 def add_on_error(callback) configuration.add_on_error(callback) end
Add the given callback to the list of on_error
callbacks
The on_error
callbacks will be called when an error is captured or reported and are passed a {Bugsnag::Report} object
Returning false from an on_error
callback will cause the error to be ignored and will prevent any remaining callbacks from being called
@param callback [Proc, Method, call] @return [void]
Source
# File lib/bugsnag.rb, line 178 def at_exit_handler_installed? @exit_handler_added ||= false end
Checks if an at_exit handler has been added.
The {Bugsnag#configure} method will add this automatically, but it can be added manually using {Bugsnag#register_at_exit}.
@return [Boolean]
Source
# File lib/bugsnag.rb, line 237 def before_notify_callbacks Bugsnag.configuration.request_data[:before_callbacks] ||= [] end
Allow access to “before notify” callbacks as an array.
These callbacks will be called whenever an error notification is being made.
@deprecated Use {Bugsnag#add_on_error} instead
Source
# File lib/bugsnag.rb, line 392 def cleaner @cleaner = nil unless defined?(@cleaner) @cleaner || LOCK.synchronize do @cleaner ||= Bugsnag::Cleaner.new(configuration) end end
Returns the client’s Cleaner
object, or creates one if not yet created.
@api private
@return [Cleaner]
Source
# File lib/bugsnag.rb, line 440 def clear_metadata(section, *args) configuration.clear_metadata(section, *args) end
Clear values from metadata
@overload clear_metadata
(section)
Clears the given section of metadata @param section [String, Symbol]
@overload clear_metadata
(section, key)
Clears the key in the given section of metadata @param section [String, Symbol] @param key [String, Symbol]
@return [void]
Source
# File lib/bugsnag.rb, line 186 def configuration @configuration = nil unless defined?(@configuration) @configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new } end
Returns the client’s Configuration
object, or creates one if not yet created.
@return [Configuration]
Source
# File lib/bugsnag.rb, line 54 def configure(validate_api_key=true) yield(configuration) if block_given? configuration.set_default_endpoints # Create the session tracker if sessions are enabled to avoid the overhead # of creating it on the first request. We skip this if we're not validating # the API key as we use this internally before the user's configure block # has run, so we don't know if sessions are enabled yet. session_tracker if validate_api_key && configuration.auto_capture_sessions check_key_valid if validate_api_key check_endpoint_setup register_at_exit end
Configure the Bugsnag
notifier application-wide settings.
Yields a {Configuration} object to use to set application settings.
@yieldparam configuration [Configuration] @return [void]
Source
# File lib/bugsnag.rb, line 450 def feature_flag_delegate configuration.request_data[:feature_flag_delegate] ||= Utility::FeatureFlagDelegate.new end
Expose the feature flag delegate internally for use when creating new Events
The Bugsnag
module’s feature_flag_delegate
is request-specific
@return [Bugsnag::Utility::FeatureFlagDelegate] @api private
Source
# File lib/bugsnag.rb, line 260 def load_integration(integration) integration = :railtie if integration == :rails if INTEGRATIONS.include?(integration) || integration == :railtie require "bugsnag/integrations/#{integration}" else configuration.debug("Integration #{integration} is not currently supported") end end
Load a specific integration.
@param integration [Symbol] One of the integrations in {INTEGRATIONS} @return [void]
Source
# File lib/bugsnag.rb, line 245 def load_integrations require "bugsnag/integrations/railtie" if defined?(Rails::Railtie) INTEGRATIONS.each do |integration| begin require "bugsnag/integrations/#{integration}" rescue LoadError end end end
Attempts to load all integrations through auto-discovery.
@return [void]
Source
# File lib/bugsnag.rb, line 403 def metadata configuration.metadata end
Global metadata added to every event
@return [Hash]
Source
# File lib/bugsnag.rb, line 75 def notify(exception, auto_notify=false, &block) unless false.equal? auto_notify or true.equal? auto_notify configuration.warn("Adding metadata/severity using a hash is no longer supported, please use block syntax instead") auto_notify = false end return unless should_deliver_notification?(exception, auto_notify) exception = NIL_EXCEPTION_DESCRIPTION if exception.nil? report = Report.new(exception, configuration, auto_notify) # If this is an auto_notify we yield the block before the any middleware is run begin yield(report) if block_given? && auto_notify rescue StandardError => e configuration.warn("Error in internal notify block: #{e}") configuration.warn("Error in internal notify block stacktrace: #{e.backtrace.inspect}") end if report.ignore? configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in auto_notify block") return end # Run internal middleware configuration.internal_middleware.run(report) if report.ignore? configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in internal middlewares") return end # Store before_middleware severity reason for future reference initial_severity = report.severity initial_reason = report.severity_reason # Run users middleware configuration.middleware.run(report) do if report.ignore? configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in user provided middleware") return end # If this is not an auto_notify then the block was provided by the user. This should be the last # block that is run as it is the users "most specific" block. begin yield(report) if block_given? && !auto_notify rescue StandardError => e configuration.warn("Error in notify block: #{e}") configuration.warn("Error in notify block stacktrace: #{e.backtrace.inspect}") end if report.ignore? configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in user provided block") return end # Test whether severity has been changed and ensure severity_reason is consistant in auto_notify case if report.severity != initial_severity report.severity_reason = { :type => Report::USER_CALLBACK_SET_SEVERITY } else report.severity_reason = initial_reason end if report.unhandled_overridden? # let the dashboard know that the unhandled flag was overridden report.severity_reason[:unhandledOverridden] = true end deliver_notification(report) end end
Explicitly notify of an exception.
Optionally accepts a block to append metadata to the yielded report.
Source
# File lib/bugsnag.rb, line 317 def on_error(&block) configuration.on_error(&block) end
Add the given block to the list of on_error
callbacks
The on_error
callbacks will be called when an error is captured or reported and are passed a {Bugsnag::Report} object
Returning false from an on_error
callback will cause the error to be ignored and will prevent any remaining callbacks from being called
@return [void]
Source
# File lib/bugsnag.rb, line 216 def pause_session session_tracker.pause_session end
Stop any events being attributed to the current session until it is resumed or a new session is started
@see resume_session
@return [void]
Source
# File lib/bugsnag.rb, line 154 def register_at_exit return if at_exit_handler_installed? @exit_handler_added = true at_exit do if $! exception = unwrap_bundler_exception($!) Bugsnag.notify(exception, true) do |report| report.severity = 'error' report.severity_reason = { :type => Bugsnag::Report::UNHANDLED_EXCEPTION } end end end end
Registers an at_exit function to automatically catch errors on exit.
@return [void]
Source
# File lib/bugsnag.rb, line 344 def remove_on_error(callback) configuration.remove_on_error(callback) end
Remove the given callback from the list of on_error
callbacks
Note that this must be the same Proc instance that was passed to {Bugsnag#add_on_error}, otherwise it will not be removed
@param callback [Proc] @return [void]
Source
# File lib/bugsnag.rb, line 227 def resume_session session_tracker.resume_session end
Resume the current session if it was previously paused. If there is no current session, a new session will be started
@see pause_session
@return [Boolean] true if a paused session was resumed
Source
# File lib/bugsnag.rb, line 195 def session_tracker @session_tracker = nil unless defined?(@session_tracker) @session_tracker || LOCK.synchronize { @session_tracker ||= Bugsnag::SessionTracker.new} end
Returns the client’s SessionTracker
object, or creates one if not yet created.
@return [SessionTracker]
Source
# File lib/bugsnag.rb, line 205 def start_session session_tracker.start_session end
Starts a new session, which allows Bugsnag
to track error rates across releases
@return [void]
Private Class Methods
Source
# File lib/bugsnag.rb, line 464 def abort_reason(exception, auto_notify) if !configuration.auto_notify && auto_notify "Not notifying because auto_notify is disabled" elsif !configuration.valid_api_key? "Not notifying due to an invalid api_key" elsif !configuration.should_notify_release_stage? "Not notifying due to notify_release_stages :#{configuration.notify_release_stages.inspect}" elsif exception.respond_to?(:skip_bugsnag) && exception.skip_bugsnag "Not notifying due to skip_bugsnag flag" end end
Source
# File lib/bugsnag.rb, line 526 def check_endpoint_setup notify_set = configuration.notify_endpoint && configuration.notify_endpoint != Bugsnag::Configuration::DEFAULT_NOTIFY_ENDPOINT && configuration.notify_endpoint != Bugsnag::Configuration::HUB_NOTIFY_ENDPOINT session_set = configuration.session_endpoint && configuration.session_endpoint != Bugsnag::Configuration::DEFAULT_SESSION_ENDPOINT && configuration.session_endpoint != Bugsnag::Configuration::HUB_SESSION_ENDPOINT if notify_set && !session_set configuration.warn("The session endpoint has not been set, all further session capturing will be disabled") configuration.disable_sessions elsif !notify_set && session_set raise ArgumentError, "The session endpoint cannot be modified without the notify endpoint" end end
Verifies the current endpoint setup
If only a notify_endpoint has been set, session tracking will be disabled If only a session_endpoint has been set, and ArgumentError will be raised
Source
# File lib/bugsnag.rb, line 513 def check_key_valid @key_warning = false unless defined?(@key_warning) if !configuration.valid_api_key? && !@key_warning configuration.warn("No valid API key has been set, notifications will not be sent") @key_warning = true end end
Check if the API key is valid and warn (once) if it is not
Source
# File lib/bugsnag.rb, line 481 def deliver_notification(report) configuration.info("Notifying #{configuration.notify_endpoint} of #{report.exceptions.last[:errorClass]}") options = { headers: report.headers } delivery_method = Bugsnag::Delivery[configuration.delivery_method] if delivery_method.respond_to?(:serialize_and_deliver) delivery_method.serialize_and_deliver( configuration.notify_endpoint, proc { report_to_json(report) }, configuration, options ) else delivery_method.deliver( configuration.notify_endpoint, report_to_json(report), configuration, options ) end leave_breadcrumb( report.summary[:error_class], report.summary, Bugsnag::Breadcrumbs::ERROR_BREADCRUMB_TYPE, :auto ) end
Deliver the notification to Bugsnag
@param report [Report] @return void
Source
# File lib/bugsnag.rb, line 549 def report_to_json(report) cleaned = cleaner.clean_object(report.as_json) trimmed = Bugsnag::Helpers.trim_if_needed(cleaned) ::JSON.dump(trimmed) end
Convert the Report
object to JSON
We ensure the report is safe to send by removing recursion, fixing encoding errors and redacting metadata according to “meta_data_filters”
@param report [Report] @return [String]
Source
# File lib/bugsnag.rb, line 456 def should_deliver_notification?(exception, auto_notify) return false unless configuration.enable_events reason = abort_reason(exception, auto_notify) configuration.debug(reason) unless reason.nil? reason.nil? end
Source
# File lib/bugsnag.rb, line 566 def unwrap_bundler_exception(exception) running_in_bundler = ENV.include?('BUNDLE_BIN_PATH') # See if this exception came from Bundler's 'with_friendly_errors' method return exception unless running_in_bundler return exception unless exception.is_a?(SystemExit) return exception unless exception.respond_to?(:cause) return exception unless exception.backtrace.first.include?('/bundler/friendly_errors.rb') return exception if exception.cause.nil? unwrapped = exception.cause # We may need to unwrap another level if the exception came from running # an executable file directly (i.e. 'bundle exec <file>'). In this case # there can be a SystemExit from 'with_friendly_errors' _and_ a SystemExit # from 'kernel_load' return unwrapped unless unwrapped.is_a?(SystemExit) return unwrapped unless unwrapped.backtrace.first.include?('/bundler/cli/exec.rb') return unwrapped if unwrapped.cause.nil? unwrapped.cause end
When running a script with ‘bundle exec’, uncaught exceptions will be converted to “friendly errors” which has the side effect of wrapping them in a SystemExit
By default we ignore SystemExit, so need to unwrap the original exception in order to avoid ignoring real errors
@param exception [Exception] @return [Exception]