Skip to content

Commit

Permalink
Release v6.16.0
Browse files Browse the repository at this point in the history
  • Loading branch information
imjoehaines authored Aug 12, 2020
2 parents bd97e4c + 819b0a3 commit 0afe6b6
Show file tree
Hide file tree
Showing 32 changed files with 294 additions and 94 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ Metrics/BlockNesting:
# Offense count: 4
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 174
Max: 184

# Offense count: 15
# Configuration parameters: IgnoredMethods.
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
Changelog
=========

## 6.16.0 (12 August 2020)

### Enhancements

* Set default Delayed Job error context to job class
| [#499](https://github.com/bugsnag/bugsnag-ruby/pull/499)
| [Mike Stewart](https://github.com/mike-stewart)

* The `BUGSNAG_RELEASE_STAGE` environment variable can now be used to set the release stage. Previously this was only used in Rails applications
| [#613](https://github.com/bugsnag/bugsnag-ruby/pull/613)

* Add support for runtime versions to Delayed Job, Mailman and Shoryuken integrations
| [#620](https://github.com/bugsnag/bugsnag-ruby/pull/620)

* Reduce the size of the bundled gem
| [#571](https://github.com/bugsnag/bugsnag-ruby/pull/571)
| [t-richards](https://github.com/t-richards)

* Move serialization of Reports onto the background thread when using the thread_queue delivery method
| [#623](https://github.com/bugsnag/bugsnag-ruby/pull/623)

## Fixes

* The `app_type` configuration option should no longer be overwritten by Bugsnag and integrations should set this more consistently
| [#619](https://github.com/bugsnag/bugsnag-ruby/pull/619)

## 6.15.0 (27 July 2020)

### Enhancements
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ group :coverage, optional: true do
end

group :rubocop, optional: true do
gem 'rubocop', '~> 0.83'
gem 'rubocop', '~> 0.88.0'
end

group :sidekiq, optional: true do
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.15.0
6.16.0
2 changes: 1 addition & 1 deletion bugsnag.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Gem::Specification.new do |s|
s.homepage = "https://github.com/bugsnag/bugsnag-ruby"
s.licenses = ["MIT"]

s.files = `git ls-files`.split("\n").reject {|file| file.start_with? "example/"}
s.files = `git ls-files -z lib bugsnag.gemspec VERSION`.split("\x0")
s.extra_rdoc_files = [
"LICENSE.txt",
"README.md",
Expand Down
20 changes: 20 additions & 0 deletions features/delayed_job.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Scenario: An unhandled RuntimeError sends a report with arguments
And the event "metaData.job.payload.display_name" equals "TestModel.fail_with_args"
And the event "metaData.job.payload.method_name" equals "fail_with_args"
And the payload field "events.0.metaData.job.payload.args.0" equals "Test"
And the event "device.runtimeVersions.delayed_job" equals "4.1.8"

Scenario: A handled exception sends a report
Given I run the service "delayed_job" with the command "bundle exec rake delayed_job_tests:notify_with_args"
Expand All @@ -34,3 +35,22 @@ Scenario: A handled exception sends a report
And the event "metaData.job.payload.display_name" equals "TestModel.notify_with_args"
And the event "metaData.job.payload.method_name" equals "notify_with_args"
And the payload field "events.0.metaData.job.payload.args.0" equals "Test"
And the event "device.runtimeVersions.delayed_job" equals "4.1.8"

Scenario: The report context uses the class name if no display name is available
Given I run the service "delayed_job" with the command "bundle exec rake delayed_job_tests:report_context"
And I wait to receive a request
Then the request is valid for the error reporting API version "4.0" for the "Ruby Bugsnag Notifier"
And the event "unhandled" is true
And the event "severity" equals "error"
And the event "context" equals "TestReportContextJob"
And the event "severityReason.type" equals "unhandledExceptionMiddleware"
And the event "severityReason.attributes.framework" equals "DelayedJob"
And the exception "errorClass" equals "RuntimeError"
And the event "metaData.job.class" equals "Delayed::Backend::ActiveRecord::Job"
And the event "metaData.job.id" is not null
And the event "metaData.job.attempt" equals 1
And the event "metaData.job.max_attempts" equals 1
And the event "metaData.job.payload.display_name" is null
And the event "metaData.job.payload.method_name" is null
And the event "device.runtimeVersions.delayed_job" equals "4.1.8"
6 changes: 5 additions & 1 deletion features/fixtures/delayed_job/app/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace :delayed_job_tests do
task :notify_with_args do
run_delayed_job_test('"TestModel.delay.notify_with_args(\"Test\")"')
end

task :report_context do
run_delayed_job_test('"Delayed::Job.enqueue TestReportContextJob.new"')
end
end

def run_delayed_job_test(command)
Expand All @@ -21,4 +25,4 @@ def run_delayed_job_test(command)
end
system("rails runner #{command}")
Process.wait
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class TestReportContextJob < ApplicationJob
queue_as :default

def perform(*)
raise "oh dear"
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT"
config.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS"
config.auto_capture_sessions = ENV["BUGSNAG_AUTO_CAPTURE_SESSIONS"] == "true"
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
config.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
config.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] == "true"
end
3 changes: 1 addition & 2 deletions features/fixtures/plain/app/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def configure_using_environment
conf.proxy_password = ENV["BUGSNAG_PROXY_PASSWORD"] if ENV.include? "BUGSNAG_PROXY_PASSWORD"
conf.proxy_port = ENV["BUGSNAG_PROXY_PORT"] if ENV.include? "BUGSNAG_PROXY_PORT"
conf.proxy_user = ENV["BUGSNAG_PROXY_USER"] if ENV.include? "BUGSNAG_PROXY_USER"
conf.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
conf.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] != "false"
conf.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
conf.timeout = ENV["BUGSNAG_TIMEOUT"] if ENV.include? "BUGSNAG_TIMEOUT"
Expand All @@ -35,4 +34,4 @@ def add_at_exit
Bugsnag.notify($!, true)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT"
config.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS"
config.auto_capture_sessions = ENV["BUGSNAG_AUTO_CAPTURE_SESSIONS"] == "true" unless ENV["USE_DEFAULT_AUTO_CAPTURE_SESSIONS"] == "true"
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
config.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
config.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] == "true"
config.meta_data_filters << 'filtered_parameter'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT"
config.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS"
config.auto_capture_sessions = ENV["BUGSNAG_AUTO_CAPTURE_SESSIONS"] == "true" unless ENV["USE_DEFAULT_AUTO_CAPTURE_SESSIONS"] == "true"
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
config.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
config.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] == "true"
config.meta_data_filters << 'filtered_parameter'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT"
config.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS"
config.auto_capture_sessions = ENV["BUGSNAG_AUTO_CAPTURE_SESSIONS"] == "true" unless ENV["USE_DEFAULT_AUTO_CAPTURE_SESSIONS"] == "true"
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
config.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
config.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] == "true"
config.meta_data_filters << 'filtered_parameter'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config.project_root = ENV["BUGSNAG_PROJECT_ROOT"] if ENV.include? "BUGSNAG_PROJECT_ROOT"
config.ignore_classes << lambda { |ex| ex.class.to_s == ENV["BUGSNAG_IGNORE_CLASS"] } if ENV.include? "BUGSNAG_IGNORE_CLASS"
config.auto_capture_sessions = ENV["BUGSNAG_AUTO_CAPTURE_SESSIONS"] == "true" unless ENV["USE_DEFAULT_AUTO_CAPTURE_SESSIONS"] == "true"
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] if ENV.include? "BUGSNAG_RELEASE_STAGE"
config.send_code = ENV["BUGSNAG_SEND_CODE"] != "false"
config.send_environment = ENV["BUGSNAG_SEND_ENVIRONMENT"] == "true"
config.meta_data_filters << 'filtered_parameter'
Expand Down
30 changes: 20 additions & 10 deletions lib/bugsnag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,25 @@ def abort_reason(exception, auto_notify)
def deliver_notification(report)
configuration.info("Notifying #{configuration.notify_endpoint} of #{report.exceptions.last[:errorClass]}")

payload = report_to_json(report)
options = {:headers => report.headers}

Bugsnag::Delivery[configuration.delivery_method].deliver(
configuration.notify_endpoint,
payload,
configuration,
options
)
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],
Expand Down Expand Up @@ -353,7 +363,7 @@ def check_endpoint_setup
# encoding errors and redacting metadata according to "meta_data_filters"
#
# @param report [Report]
# @return string
# @return [String]
def report_to_json(report)
cleaned = cleaner.clean_object(report.as_json)
trimmed = Bugsnag::Helpers.trim_if_needed(cleaned)
Expand Down
50 changes: 49 additions & 1 deletion lib/bugsnag/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class Configuration
attr_accessor :send_code
attr_accessor :project_root
attr_accessor :app_version
attr_accessor :app_type
attr_accessor :meta_data_filters
attr_accessor :logger
attr_accessor :middleware
Expand Down Expand Up @@ -116,6 +115,7 @@ def initialize
self.runtime_versions["ruby"] = RUBY_VERSION
self.runtime_versions["jruby"] = JRUBY_VERSION if defined?(JRUBY_VERSION)
self.timeout = 15
self.release_stage = ENV['BUGSNAG_RELEASE_STAGE']
self.notify_release_stages = nil
self.auto_capture_sessions = true

Expand Down Expand Up @@ -197,6 +197,54 @@ def default_delivery_method=(delivery_method)
@default_delivery_method = delivery_method
end

##
# Get the type of application executing the current code
#
# This is usually used to represent if you are running in a Rails server,
# Sidekiq job, Rake task etc... Bugsnag will automatically detect most
# application types for you
#
# @return [String, nil]
def app_type
@app_type || @detected_app_type
end

##
# Set the type of application executing the current code
#
# If an app_type is set, this will be used instead of the automatically
# detected app_type that Bugsnag would otherwise use
#
# @param app_type [String]
# @return [void]
def app_type=(app_type)
@app_type = app_type
end

##
# Get the detected app_type, which is used when one isn't set explicitly
#
# @api private
#
# @return [String, nil]
def detected_app_type
@detected_app_type
end

##
# Set the detected app_type, which is used when one isn't set explicitly
#
# This allows Bugsnag's integrations to say 'this is a Rails app' while
# allowing the user to overwrite this if they wish
#
# @api private
#
# @param app_type [String]
# @return [void]
def detected_app_type=(app_type)
@detected_app_type = app_type
end

##
# Indicates whether the notifier should send a notification based on the
# configured release stage.
Expand Down
21 changes: 18 additions & 3 deletions lib/bugsnag/delivery/thread_queue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ class ThreadQueue < Synchronous

class << self
##
# Queues a given payload to be delivered asynchronously.
def deliver(url, body, configuration, options={})
# Queues a given payload to be delivered asynchronously
#
# @param url [String]
# @param get_payload [Proc] A Proc that will return the payload.
# @param configuration [Bugsnag::Configuration]
# @param options [Hash]
# @return [void]
def serialize_and_deliver(url, get_payload, configuration, options={})
@configuration = configuration

start_once!
Expand All @@ -21,7 +27,16 @@ def deliver(url, body, configuration, options={})
end

# Add delivery to the worker thread
@queue.push proc { super(url, body, configuration, options) }
@queue.push(proc do
begin
payload = get_payload.call
rescue StandardError => e
configuration.warn("Notification to #{url} failed, #{e.inspect}")
configuration.warn(e.backtrace)
end

Synchronous.deliver(url, payload, configuration, options) unless payload.nil?
end)
end

private
Expand Down
14 changes: 13 additions & 1 deletion lib/bugsnag/integrations/delayed_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,23 @@
module Delayed
module Plugins
class Bugsnag < ::Delayed::Plugin
##
# DelayedJob doesn't have an easy way to fetch its version, but we can use
# Gem.loaded_specs to get the version instead
def self.delayed_job_version
::Gem.loaded_specs['delayed_job'].version.to_s
rescue StandardError
# Explicitly return nil to prevent Rubocop complaining of a suppressed exception
nil
end

callbacks do |lifecycle|
lifecycle.around(:invoke_job) do |job, *args, &block|
begin
::Bugsnag.configuration.app_type = 'delayed_job'
::Bugsnag.configuration.detected_app_type = 'delayed_job'
::Bugsnag.configuration.runtime_versions['delayed_job'] = delayed_job_version if defined?(::Gem)
::Bugsnag.configuration.set_request_data(:delayed_job, job)

block.call(job, *args)
rescue Exception => exception
::Bugsnag.notify(exception, true) do |report|
Expand Down
3 changes: 2 additions & 1 deletion lib/bugsnag/integrations/mailman.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class Mailman

def initialize
Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Mailman)
Bugsnag.configuration.app_type = "mailman"
Bugsnag.configuration.detected_app_type = "mailman"
Bugsnag.configuration.runtime_versions["mailman"] = ::Mailman::VERSION
end

##
Expand Down
3 changes: 2 additions & 1 deletion lib/bugsnag/integrations/que.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
end
end

Bugsnag.configuration.app_type ||= "que"
Bugsnag.configuration.detected_app_type = "que"

if defined?(::Que::Version)
Bugsnag.configuration.runtime_versions["que"] = ::Que::Version
elsif defined?(::Que::VERSION)
Expand Down
4 changes: 3 additions & 1 deletion lib/bugsnag/integrations/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ def initialize(app)
config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)

# Set environment data for payload
config.app_type ||= "rack"
# Note we only set the detected app_type if it's not already set. This
# ensures we don't overwrite the value set by the Railtie
config.detected_app_type ||= "rack"
config.runtime_versions["rack"] = ::Rack.release if defined?(::Rack)
config.runtime_versions["sinatra"] = ::Sinatra::VERSION if defined?(::Sinatra)
end
Expand Down
Loading

0 comments on commit 0afe6b6

Please sign in to comment.