Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added unhandled functionality, updated tests and integrations #368

Merged
merged 17 commits into from
Oct 2, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
50 changes: 35 additions & 15 deletions lib/bugsnag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,37 @@ def configure
end

# Explicitly notify of an exception
def notify(exception, auto_notify=false, &block)
if auto_notify && !configuration.auto_notify
def notify(exception, &block)
report = Report.new(exception, configuration)
send_report(report, false, &block)
end

# For automatic notification of exceptions
def auto_notify(exception, severity_reason, &block)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we need the auto_notify method. If you look where we build and send the report blocks when auto_notify is set to true are run first so we can change the reports in the block for auto notifications.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I would just call notify like we did before, just telling notify that this is an auto_notify. Then in the block you can set the severity reason and the severity. Its weird that severity is set in the block, and severity reason outside it right now.

if !configuration.auto_notify
configuration.debug("Not notifying because auto_notify is disabled")
return
end

report = Report.new(exception, configuration, true, severity_reason)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could set the severity reason in here to be error?


send_report(report, true, &block)
end

# Configuration getters
def configuration
@configuration = nil unless defined?(@configuration)
@configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
end

# Allow access to "before notify" callbacks
def before_notify_callbacks
Bugsnag.configuration.request_data[:before_callbacks] ||= []
end

private
def send_report(report, auto_notify, &block)

if !configuration.valid_api_key?
configuration.debug("Not notifying due to an invalid api_key")
return
Expand All @@ -49,8 +74,6 @@ def notify(exception, auto_notify=false, &block)
return
end

report = Report.new(exception, configuration)

# If this is an auto_notify we yield the block before the any middleware is run
yield(report) if block_given? && auto_notify
if report.ignore?
Expand All @@ -65,6 +88,9 @@ def notify(exception, auto_notify=false, &block)
return
end

# Store default severity for future reference
initial_severity = report.severity

# Run users middleware
configuration.middleware.run(report) do
if report.ignore?
Expand All @@ -80,24 +106,18 @@ def notify(exception, auto_notify=false, &block)
return
end

# Test whether severity has been changed
if report.severity != initial_severity
report.default_severity = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could make this a little clearer imo with report.default_severity = report.severity == initial_severity

end

# Deliver
configuration.info("Notifying #{configuration.endpoint} of #{report.exceptions.last[:errorClass]}")
payload_string = ::JSON.dump(Bugsnag::Helpers.trim_if_needed(report.as_json))
configuration.debug("Payload: #{payload_string}")
Bugsnag::Delivery[configuration.delivery_method].deliver(configuration.endpoint, payload_string, configuration)
end
end

# Configuration getters
def configuration
@configuration = nil unless defined?(@configuration)
@configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
end

# Allow access to "before notify" callbacks
def before_notify_callbacks
Bugsnag.configuration.request_data[:before_callbacks] ||= []
end
end
end

Expand Down
7 changes: 6 additions & 1 deletion lib/bugsnag/integrations/mailman.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ def call(mail)
yield
rescue Exception => ex
raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
Bugsnag.notify(ex, true) do |report|
Bugsnag.auto_notify(ex, {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "mailman"
}
}) do |report|
report.severity = "error"
end
raise
Expand Down
14 changes: 12 additions & 2 deletions lib/bugsnag/integrations/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ def call(env)
response = @app.call(env)
rescue Exception => raised
# Notify bugsnag of rack exceptions
Bugsnag.notify(raised, true) do |report|
Bugsnag.auto_notify(raised, {
:type => "middleware_handler",
:attirbutes => {
:name => "rack"
}
}) do |report|
report.severity = "error"
end

Expand All @@ -43,7 +48,12 @@ def call(env)

# Notify bugsnag of rack exceptions
if env["rack.exception"]
Bugsnag.notify(env["rack.exception"], true) do |report|
Bugsnag.auto_notify(env["rack.exception"], {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "rack"
}
}) do |report|
report.severity = "error"
end
end
Expand Down
7 changes: 6 additions & 1 deletion lib/bugsnag/integrations/rails/active_record_rescue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ def run_callbacks(kind, *args, &block)
super
rescue StandardError => exception
# This exception will NOT be escalated, so notify it here.
Bugsnag.notify(exception, true) do |report|
Bugsnag.auto_notify(exception, {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "active record"
}
}) do |report|
report.severity = "error"
end
raise
Expand Down
7 changes: 6 additions & 1 deletion lib/bugsnag/integrations/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ class Railtie < Rails::Railtie
runner do
at_exit do
if $!
Bugsnag.notify($!, true) do |report|
Bugsnag.auto_notify($!, {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "railtie"
}
}) do |report|
report.severity = "error"
end
end
Expand Down
7 changes: 6 additions & 1 deletion lib/bugsnag/integrations/rake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def execute_with_bugsnag(args=nil)
execute_without_bugsnag(args)

rescue Exception => ex
Bugsnag.notify(ex, true) do |report|
Bugsnag.auto_notify(ex, {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "rake"
}
}) do |report|
report.severity = "error"
end
raise
Expand Down
7 changes: 6 additions & 1 deletion lib/bugsnag/integrations/resque.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ def self.add_failure_backend
end

def save
Bugsnag.notify(exception, true) do |report|
Bugsnag.auto_notify(exception, {
:type => "middleware",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware_handler

:attributes => {
:name => "mailman"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resque

}
}) do |report|
report.severity = "error"
report.meta_data.merge!({:context => "#{payload['class']}@#{queue}", :payload => payload, :delivery_method => :synchronous})
end
Expand Down
10 changes: 9 additions & 1 deletion lib/bugsnag/integrations/sidekiq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ def call(worker, msg, queue)
yield
rescue Exception => ex
raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
Bugsnag.notify(ex, true) do |report|
Bugsnag.auto_notify(
ex,
{
:type => 'middleware_handler',
:attributes => {
:name => "sidekiq"
}
}
) do |report|
report.severity = "error"
end
raise
Expand Down
13 changes: 12 additions & 1 deletion lib/bugsnag/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Report
attr_accessor :app_version
attr_accessor :configuration
attr_accessor :context
attr_accessor :default_severity
attr_accessor :delivery_method
attr_accessor :exceptions
attr_accessor :hostname
Expand All @@ -27,8 +28,10 @@ class Report
attr_accessor :severity
attr_accessor :user

def initialize(exception, passed_configuration)
def initialize(exception, passed_configuration, unhandled=false, severity_reason=nil)
@should_ignore = false
@unhandled = unhandled
@severity_reason = severity_reason

self.configuration = passed_configuration

Expand All @@ -43,6 +46,7 @@ def initialize(exception, passed_configuration)
self.meta_data = {}
self.release_stage = configuration.release_stage
self.severity = "warning"
self.default_severity = true
self.user = {}
end

Expand Down Expand Up @@ -77,16 +81,23 @@ def as_json
type: app_type
},
context: context,
defaultSeverity: default_severity,
device: {
hostname: hostname
},
exceptions: exceptions,
groupingHash: grouping_hash,
payloadVersion: CURRENT_PAYLOAD_VERSION,
severity: severity,
unhandled: @unhandled,
user: user
}

# add severity_reason if necessary
if @unhandled
payload_event[:severityReason] = @severity_reason
end

# cleanup character encodings
payload_event = Bugsnag::Cleaner.clean_object_encoding(payload_event)

Expand Down
9 changes: 8 additions & 1 deletion lib/bugsnag/tasks/bugsnag.rake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ namespace :bugsnag do
begin
raise RuntimeError.new("Bugsnag test exception")
rescue => e
Bugsnag.notify(e, {:context => "rake#test_exception"})
Bugsnag.auto_notify(e, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine to just be a normal notify, doesnt need to be an auto_notify. Its just a way of people testing their bugsnag installations

:type => "middleware",
:attributes => {
:name => "rake"
}
}) do |report|
report.context = "rake#test_exception"
end
end
end
end
Expand Down
52 changes: 49 additions & 3 deletions spec/report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def gloops
end

it "autonotifies errors" do
Bugsnag.notify(BugsnagTestException.new("It crashed"), true) do |report|
Bugsnag.auto_notify(BugsnagTestException.new("It crashed"), {}) do |report|
report.severity = "error"
end

Expand Down Expand Up @@ -421,12 +421,12 @@ def gloops
}
end

it "does not send a notification if auto_notify is false" do
it "does not send an automatic notification if auto_notify is false" do
Bugsnag.configure do |config|
config.auto_notify = false
end

Bugsnag.notify(BugsnagTestException.new("It crashed"), true)
Bugsnag.auto_notify(BugsnagTestException.new("It crashed"), true)

expect(Bugsnag).not_to have_sent_notification
end
Expand Down Expand Up @@ -888,6 +888,52 @@ def gloops
}
end

it 'should use defaults when notify is called' do
Bugsnag.notify(BugsnagTestException.new("It crashed"))

expect(Bugsnag).to have_sent_notification{ |payload|
event = payload["events"][0]
expect(event["unhandled"]).to be false
expect(event["severityReason"].nil?).to be true
expect(event["defaultSeverity"]).to be true
}
end

it 'should attach a severity reason when auto_notify is called' do
Bugsnag.auto_notify(
BugsnagTestException.new("It crashed"),
{
:type => "middleware_handler",
:attributes => {
:name => "middleware_test"
}
}
)

expect(Bugsnag).to have_sent_notification{ |payload|
event = payload["events"][0]
expect(event["severityReason"]).to eq(
{
"type" => "middleware_handler",
"attributes" => {
"name" => "middleware_test"
}
}
)
expect(event["unhandled"]).to be true
}
end

it 'should set default_severity flag if severity is changed' do
Bugsnag.notify(BugsnagTestException.new("It crashed")) do |report|
report.severity = "info"
end

expect(Bugsnag).to have_sent_notification{ |payload|
expect(payload["events"][0]["defaultSeverity"]).to be false
}
end

if defined?(JRUBY_VERSION)

it "should work with java.lang.Throwables" do
Expand Down