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

Add errors to Report/Event #691

Merged
merged 2 commits into from
Sep 7, 2021
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Changelog
| [#689](https://github.com/bugsnag/bugsnag-ruby/pull/689)
* Add `time` (an ISO8601 string in UTC) to `device` metadata
| [#690](https://github.com/bugsnag/bugsnag-ruby/pull/690)
* Add `errors` to `Report`/`Event` containing an array of `Error` objects. The `Error` object contains `error_class`, `error_message` and `type` (always "ruby")
| [#691](https://github.com/bugsnag/bugsnag-ruby/pull/691)

### Fixes

Expand All @@ -37,6 +39,7 @@ Changelog
* The `Breadcrumb#name` attribute has been deprecated in favour of `Breadcrumb#message`
* The breadcrumb type constants in the `Bugsnag::Breadcrumbs` module has been deprecated in favour of the constants available in the `Bugsnag::BreadcrumbType` module
For example, `Bugsnag::Breadcrumbs::ERROR_BREADCRUMB_TYPE` is now available as `Bugsnag::BreadcrumbType::ERROR`
* `Report#exceptions` has been deprecated in favour of the new `errors` property

## v6.22.1 (11 August 2021)

Expand Down
9 changes: 9 additions & 0 deletions lib/bugsnag/error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Bugsnag
# @!attribute error_class
# @return [String] the error's class name
# @!attribute error_message
# @return [String] the error's message
# @!attribute type
# @return [String] the type of error (always "ruby")
Error = Struct.new(:error_class, :error_message, :type)
end
18 changes: 18 additions & 0 deletions lib/bugsnag/report.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
require "json"
require "pathname"
require "bugsnag/error"
require "bugsnag/stacktrace"

module Bugsnag
# rubocop:todo Metrics/ClassLength
class Report
NOTIFIER_NAME = "Ruby Bugsnag Notifier"
NOTIFIER_VERSION = Bugsnag::VERSION
Expand All @@ -19,6 +21,9 @@ class Report

CURRENT_PAYLOAD_VERSION = "4.0"

# @api private
ERROR_TYPE = "ruby".freeze

# Whether this report is for a handled or unhandled error
# @return [Boolean]
attr_reader :unhandled
Expand Down Expand Up @@ -51,6 +56,7 @@ class Report
attr_accessor :delivery_method

# The list of exceptions in this report
# @deprecated Use {#errors} instead
# @return [Array<Hash>]
attr_accessor :exceptions

Expand Down Expand Up @@ -99,6 +105,10 @@ class Report
# @return [Hash]
attr_accessor :user

# A list of errors in this report
# @return [Array<Error>]
attr_reader :errors

##
# Initializes a new report from an exception.
def initialize(exception, passed_configuration, auto_notify=false)
Expand All @@ -112,6 +122,7 @@ def initialize(exception, passed_configuration, auto_notify=false)

self.raw_exceptions = generate_raw_exceptions(exception)
self.exceptions = generate_exception_list
@errors = generate_error_list

self.api_key = configuration.api_key
self.app_type = configuration.app_type
Expand Down Expand Up @@ -303,6 +314,12 @@ def generate_exception_list
end
end

def generate_error_list
exceptions.map do |exception|
Error.new(exception[:errorClass], exception[:message], ERROR_TYPE)
end
end

def error_class(exception)
# The "Class" check is for some strange exceptions like Timeout::Error
# which throw the error class instead of an instance
Expand Down Expand Up @@ -345,4 +362,5 @@ def generate_raw_exceptions(exception)
exceptions
end
end
# rubocop:enable Metrics/ClassLength
end
67 changes: 67 additions & 0 deletions spec/report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,73 @@ def gloops
end
end
end

describe "#errors" do
it "has required hash keys" do
exception = RuntimeError.new("example error")
report = class_to_test.new(exception, Bugsnag.configuration)

expect(report.errors).to eq(
[Bugsnag::Error.new("RuntimeError", "example error", "ruby")]
)
end

it "includes errors that caused the top-most exception" do
begin
begin
raise "one"
rescue
Ruby21Exception.raise!("two")
end
rescue => exception
end

report = class_to_test.new(exception, Bugsnag.configuration)

expect(report.errors).to eq(
[
Bugsnag::Error.new("Ruby21Exception", "two", "ruby"),
Bugsnag::Error.new("RuntimeError", "one", "ruby")
]
)
end

it "cannot be assigned to" do
exception = RuntimeError.new("example error")
report = class_to_test.new(exception, Bugsnag.configuration)

expect(report).not_to respond_to(:errors=)
end

it "can be mutated" do
exception = RuntimeError.new("example error")
report = class_to_test.new(exception, Bugsnag.configuration)

report.errors.push("haha")
report.errors.push("haha 2")
report.errors.pop

expect(report.errors).to eq(
[
Bugsnag::Error.new("RuntimeError", "example error", "ruby"),
"haha"
]
)
end

it "contains mutable data" do
exception = RuntimeError.new("example error")
report = class_to_test.new(exception, Bugsnag.configuration)

report.errors.first.error_class = "haha"
report.errors.first.error_message = "ahah"
report.errors.first.type = "aahh"

expect(report.errors).to eq(
[Bugsnag::Error.new("haha", "ahah", "aahh")]
)
end
end
end

# rubocop:disable Metrics/BlockLength
Expand Down