Skip to content

Commit

Permalink
Merge pull request #564 from bugsnag/next
Browse files Browse the repository at this point in the history
6.12.0 release
  • Loading branch information
tomlongridge authored Aug 29, 2019
2 parents 73ab896 + e938bce commit 2fbc548
Show file tree
Hide file tree
Showing 24 changed files with 248 additions and 66 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
Changelog
=========

## 6.12.0 (28 Aug 2019)

### Enhancements

* Add Ruby (and other framework) version strings to report and session payloads (device.runtimeVersions).
| [560](https://github.com/bugsnag/bugsnag-ruby/pull/560)

* Allow symbols in breadcrumb meta data.
| [#563](https://github.com/bugsnag/bugsnag-ruby/pull/563)
| [directionless](https://github.com/directionless)

### Fixes

* Use `Module#prepend` for Rake integration when on a new enough Ruby version
to avoid infinite mutual recursion issues when something else monkey patches
`Rake::Task`.
| [#556](https://github.com/bugsnag/bugsnag-ruby/issues/556)
| [#559](https://github.com/bugsnag/bugsnag-ruby/issues/559)

* Handle `nil` values for the `job` block parameter for the Que error notifier.
This occurs under some conditions such as database connection failures.
| [#545](https://github.com/bugsnag/bugsnag-ruby/issues/545)
| [#548](https://github.com/bugsnag/bugsnag-ruby/pull/548)

## 6.11.1 (22 Jan 2019)

### Fixes
Expand Down
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ Thank you!
- Run the tests with and make sure they all pass

```
rake spec
bundle exec rake spec
```
- You will need to add the following test dependencies:
```
bundle install --with test --binstubs
```
- For adding a new integration (like support for a web framework or worker
queue), include an example in the `example/` directory showing off what
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.11.1
6.12.0
4 changes: 2 additions & 2 deletions lib/bugsnag/breadcrumbs/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ def validate(breadcrumb)
##
# Tests whether the meta_data types are non-complex objects.
#
# Acceptable types are String, Numeric, TrueClass, FalseClass, and nil.
# Acceptable types are String, Symbol, Numeric, TrueClass, FalseClass, and nil.
#
# @param value [Object] the object to be type checked
def valid_meta_data_type?(value)
value.nil? || value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(FalseClass) || value.is_a?(TrueClass)
value.nil? || value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(FalseClass) || value.is_a?(TrueClass)
end
end
end
4 changes: 4 additions & 0 deletions lib/bugsnag/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Configuration
attr_accessor :proxy_password
attr_accessor :timeout
attr_accessor :hostname
attr_accessor :runtime_versions
attr_accessor :ignore_classes
attr_accessor :auto_capture_sessions
attr_accessor :track_sessions
Expand Down Expand Up @@ -93,6 +94,9 @@ def initialize
self.send_code = true
self.meta_data_filters = Set.new(DEFAULT_META_DATA_FILTERS)
self.hostname = default_hostname
self.runtime_versions = {}
self.runtime_versions["ruby"] = RUBY_VERSION
self.runtime_versions["jruby"] = JRUBY_VERSION if defined?(JRUBY_VERSION)
self.timeout = 15
self.notify_release_stages = nil
self.auto_capture_sessions = true
Expand Down
27 changes: 15 additions & 12 deletions lib/bugsnag/integrations/que.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
require 'que'

if defined?(::Que)
handler = proc do |error, job|
begin
job = job.dup # Make sure the original job object is not mutated.
job &&= job.dup # Make sure the original job object is not mutated.

Bugsnag.notify(error, true) do |report|
job[:error_count] += 1
if job
job[:error_count] += 1

# If the job was scheduled using ActiveJob then unwrap the job details for clarity:
if job[:job_class] == "ActiveJob::QueueAdapters::QueAdapter::JobWrapper"
wrapped_job = job[:args].last
wrapped_job = wrapped_job.each_with_object({}) { |(k, v), result| result[k.to_sym] = v } # Symbolize keys
# If the job was scheduled using ActiveJob then unwrap the job details for clarity:
if job[:job_class] == "ActiveJob::QueueAdapters::QueAdapter::JobWrapper"
wrapped_job = job[:args].last
wrapped_job = wrapped_job.each_with_object({}) { |(k, v), result| result[k.to_sym] = v } # Symbolize keys

# Align key names with keys in `job`
wrapped_job[:queue] = wrapped_job.delete(:queue_name)
wrapped_job[:args] = wrapped_job.delete(:arguments)
# Align key names with keys in `job`
wrapped_job[:queue] = wrapped_job.delete(:queue_name)
wrapped_job[:args] = wrapped_job.delete(:arguments)

job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job)
job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job)
end
end

report.add_tab(:job, job)
Expand All @@ -38,9 +39,11 @@

if Que.respond_to?(:error_notifier=)
Bugsnag.configuration.app_type ||= "que"
Bugsnag.configuration.runtime_versions["que"] = ::Que::Version
Que.error_notifier = handler
elsif Que.respond_to?(:error_handler=)
Bugsnag.configuration.app_type ||= "que"
Bugsnag.configuration.runtime_versions["que"] = ::Que::Version
Que.error_handler = handler
end
end
end
3 changes: 3 additions & 0 deletions lib/bugsnag/integrations/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ def initialize(app)
config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::WardenUser) if defined?(Warden)
config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)

# Set environment data for payload
config.app_type ||= "rack"
config.runtime_versions["rack"] = ::Rack.release if defined?(::Rack)
config.runtime_versions["sinatra"] = ::Sinatra::VERSION if defined?(::Sinatra)
end
end

Expand Down
1 change: 1 addition & 0 deletions lib/bugsnag/integrations/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Railtie < ::Rails::Railtie
config.release_stage = ENV["BUGSNAG_RELEASE_STAGE"] || ::Rails.env.to_s
config.project_root = ::Rails.root.to_s
config.middleware.insert_before Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::Rails3Request
config.runtime_versions["rails"] = ::Rails::VERSION::STRING
end

ActiveSupport.on_load(:action_controller) do
Expand Down
84 changes: 58 additions & 26 deletions lib/bugsnag/integrations/rake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,68 @@

Rake::TaskManager.record_task_metadata = true

class Rake::Task

FRAMEWORK_ATTRIBUTES = {
:framework => "Rake"
}

##
# Executes the rake task with Bugsnag setup with contextual data.
def execute_with_bugsnag(args=nil)
Bugsnag.configuration.app_type ||= "rake"
old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
Bugsnag.configuration.set_request_data :bugsnag_running_task, self

execute_without_bugsnag(args)

rescue Exception => ex
Bugsnag.notify(ex, true) do |report|
report.severity = "error"
report.severity_reason = {
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
:attributes => FRAMEWORK_ATTRIBUTES
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0')
module Bugsnag
module RakeTask
FRAMEWORK_ATTRIBUTES = {
framework: 'Rake'
}

# Executes the rake task with Bugsnag setup with contextual data.
def execute(args = nil)
Bugsnag.configuration.app_type ||= "rake"
old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
Bugsnag.configuration.set_request_data :bugsnag_running_task, self
Bugsnag.configuration.runtime_versions["rake"] = ::Rake::VERSION

super
rescue Exception => ex
Bugsnag.notify(ex, true) do |report|
report.severity = "error"
report.severity_reason = {
type: Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
attributes: FRAMEWORK_ATTRIBUTES
}
end
raise
ensure
Bugsnag.configuration.set_request_data :bugsnag_running_task, old_task
end
end
raise
ensure
Bugsnag.configuration.set_request_data :bugsnag_running_task, old_task
end

alias_method :execute_without_bugsnag, :execute
alias_method :execute, :execute_with_bugsnag
Rake::Task.send(:prepend, Bugsnag::RakeTask)
else
class Rake::Task
FRAMEWORK_ATTRIBUTES = {
framework: 'Rake'
}

##
# Executes the rake task with Bugsnag setup with contextual data.
def execute_with_bugsnag(args=nil)
Bugsnag.configuration.app_type ||= "rake"
old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
Bugsnag.configuration.set_request_data :bugsnag_running_task, self
Bugsnag.configuration.runtime_versions["rake"] = ::Rake::VERSION

execute_without_bugsnag(args)
rescue Exception => ex
Bugsnag.notify(ex, true) do |report|
report.severity = "error"
report.severity_reason = {
type: Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
attributes: FRAMEWORK_ATTRIBUTES
}
end
raise
ensure
Bugsnag.configuration.set_request_data :bugsnag_running_task, old_task
end

alias_method :execute_without_bugsnag, :execute
alias_method :execute, :execute_with_bugsnag
end
end

Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Rake)
2 changes: 2 additions & 0 deletions lib/bugsnag/integrations/resque.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ def save
Resque.after_fork do
Bugsnag.configuration.app_type = "resque"
Bugsnag.configuration.default_delivery_method = :synchronous
Bugsnag.configuration.runtime_versions["resque"] = ::Resque::VERSION
end
else
Resque.before_first_fork do
Bugsnag.configuration.app_type = "resque"
Bugsnag.configuration.default_delivery_method = :synchronous
Bugsnag.configuration.runtime_versions["resque"] = ::Resque::VERSION
end
end
1 change: 1 addition & 0 deletions lib/bugsnag/integrations/sidekiq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def initialize
Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Sidekiq)
Bugsnag.configuration.app_type = "sidekiq"
Bugsnag.configuration.default_delivery_method = :synchronous
Bugsnag.configuration.runtime_versions["sidekiq"] = ::Sidekiq::VERSION
end

def call(worker, msg, queue)
Expand Down
7 changes: 0 additions & 7 deletions lib/bugsnag/middleware/rails3_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ def call(report)
})

report.user["id"] = client_ip

# Add the rails version
if report.configuration.send_environment
report.add_tab(:environment, {
:railsVersion => Rails::VERSION::STRING
})
end
end

@bugsnag.call(report)
Expand Down
5 changes: 4 additions & 1 deletion lib/bugsnag/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Report
attr_accessor :delivery_method
attr_accessor :exceptions
attr_accessor :hostname
attr_accessor :runtime_versions
attr_accessor :grouping_hash
attr_accessor :meta_data
attr_accessor :raw_exceptions
Expand All @@ -55,6 +56,7 @@ def initialize(exception, passed_configuration, auto_notify=false)
self.breadcrumbs = []
self.delivery_method = configuration.delivery_method
self.hostname = configuration.hostname
self.runtime_versions = configuration.runtime_versions.dup
self.meta_data = {}
self.release_stage = configuration.release_stage
self.severity = auto_notify ? "error" : "warning"
Expand Down Expand Up @@ -97,7 +99,8 @@ def as_json
},
context: context,
device: {
hostname: hostname
hostname: hostname,
runtimeVersions: runtime_versions
},
exceptions: exceptions,
groupingHash: grouping_hash,
Expand Down
3 changes: 2 additions & 1 deletion lib/bugsnag/session_tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def deliver(session_payload)
:version => Bugsnag::Report::NOTIFIER_VERSION
},
:device => {
:hostname => Bugsnag.configuration.hostname
:hostname => Bugsnag.configuration.hostname,
:runtimeVersions => Bugsnag.configuration.runtime_versions
},
:app => {
:version => Bugsnag.configuration.app_version,
Expand Down
1 change: 1 addition & 0 deletions spec/breadcrumbs/validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@

meta_data = {
:string => "This is a string",
:symbol => :this_is_a_symbol,
:integer => 12345,
:float => 12345.6789,
:false => false,
Expand Down
31 changes: 31 additions & 0 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,37 @@
end
end

describe "#hostname" do
it "has a default value" do
expect(subject.hostname.length).to be > 0
end

it "has a value set by Socket" do
expect(subject.hostname).to eq(Socket.gethostname)
end

it "has a value set by DYNO environment variable" do
ENV['DYNO'] = 'localhost'
expect(subject.hostname).to eq("localhost")
end

after do
ENV['DYNO'] = nil
end
end

describe "#runtime_versions" do
it "has a default value" do
expect(subject.runtime_versions.length).to be > 0
expect(subject.runtime_versions["ruby"]).to eq(RUBY_VERSION)
end

it "has a settable value" do
subject.runtime_versions["ruby"] = '9.9.9'
expect(subject.runtime_versions["ruby"]).to eq('9.9.9')
end
end

describe "logger" do
class TestLogger
attr_accessor :logs
Expand Down
12 changes: 12 additions & 0 deletions spec/fixtures/tasks/Rakefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0')
# Mixing Module#prepend with alias_method can sometimes lead to infinite
# mutual recursion, so this is to test that it doesn't happen.
mod = Module.new do
def execute(args = nil)
puts 'In module prepended to Rake::Task'
super
end
end
Rake::Task.send(:prepend, mod)
end

require "bugsnag/integrations/rake"

namespace :test do
Expand Down
Loading

0 comments on commit 2fbc548

Please sign in to comment.