bugsnag 5.5.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +33 -11
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +20 -0
  5. data/Rakefile +19 -12
  6. data/UPGRADING.md +58 -0
  7. data/VERSION +1 -1
  8. data/bugsnag.gemspec +0 -9
  9. data/lib/bugsnag.rb +64 -86
  10. data/lib/bugsnag/configuration.rb +42 -26
  11. data/lib/bugsnag/delivery.rb +9 -0
  12. data/lib/bugsnag/delivery/synchronous.rb +3 -5
  13. data/lib/bugsnag/delivery/thread_queue.rb +4 -2
  14. data/lib/bugsnag/helpers.rb +5 -16
  15. data/lib/bugsnag/{delayed_job.rb → integrations/delayed_job.rb} +15 -7
  16. data/lib/bugsnag/{mailman.rb → integrations/mailman.rb} +13 -11
  17. data/lib/bugsnag/{que.rb → integrations/que.rb} +11 -11
  18. data/lib/bugsnag/{rack.rb → integrations/rack.rb} +22 -23
  19. data/lib/bugsnag/{rails → integrations/rails}/active_record_rescue.rb +9 -7
  20. data/lib/bugsnag/{rails → integrations/rails}/controller_methods.rb +0 -9
  21. data/lib/bugsnag/{railtie.rb → integrations/railtie.rb} +24 -21
  22. data/lib/bugsnag/{rake.rb → integrations/rake.rb} +12 -9
  23. data/lib/bugsnag/{resque.rb → integrations/resque.rb} +12 -9
  24. data/lib/bugsnag/integrations/shoryuken.rb +49 -0
  25. data/lib/bugsnag/{sidekiq.rb → integrations/sidekiq.rb} +13 -9
  26. data/lib/bugsnag/middleware/callbacks.rb +4 -8
  27. data/lib/bugsnag/middleware/classify_error.rb +7 -13
  28. data/lib/bugsnag/middleware/clearance_user.rb +8 -8
  29. data/lib/bugsnag/middleware/exception_meta_data.rb +34 -0
  30. data/lib/bugsnag/middleware/ignore_error_class.rb +21 -0
  31. data/lib/bugsnag/middleware/mailman.rb +4 -4
  32. data/lib/bugsnag/middleware/rack_request.rb +13 -13
  33. data/lib/bugsnag/middleware/rails3_request.rb +10 -10
  34. data/lib/bugsnag/middleware/rake.rb +5 -5
  35. data/lib/bugsnag/middleware/sidekiq.rb +5 -5
  36. data/lib/bugsnag/middleware/suggestion_data.rb +30 -0
  37. data/lib/bugsnag/middleware/warden_user.rb +6 -6
  38. data/lib/bugsnag/middleware_stack.rb +5 -5
  39. data/lib/bugsnag/report.rb +187 -0
  40. data/lib/bugsnag/stacktrace.rb +113 -0
  41. data/lib/bugsnag/tasks/bugsnag.rake +2 -70
  42. data/spec/cleaner_spec.rb +6 -0
  43. data/spec/configuration_spec.rb +1 -1
  44. data/spec/fixtures/middleware/internal_info_setter.rb +3 -3
  45. data/spec/fixtures/middleware/public_info_setter.rb +3 -3
  46. data/spec/fixtures/tasks/Rakefile +2 -3
  47. data/spec/integration_spec.rb +5 -20
  48. data/spec/{delayed_job_spec.rb → integrations/delayed_job_spec.rb} +0 -0
  49. data/spec/integrations/sidekiq_spec.rb +34 -0
  50. data/spec/middleware_spec.rb +108 -35
  51. data/spec/rack_spec.rb +1 -1
  52. data/spec/{notification_spec.rb → report_spec.rb} +226 -209
  53. data/spec/spec_helper.rb +18 -0
  54. data/spec/{code_spec.rb → stacktrace_spec.rb} +1 -1
  55. metadata +23 -139
  56. data/.document +0 -5
  57. data/lib/bugsnag/capistrano.rb +0 -7
  58. data/lib/bugsnag/capistrano2.rb +0 -32
  59. data/lib/bugsnag/delay/resque.rb +0 -21
  60. data/lib/bugsnag/deploy.rb +0 -35
  61. data/lib/bugsnag/middleware/rails2_request.rb +0 -52
  62. data/lib/bugsnag/notification.rb +0 -506
  63. data/lib/bugsnag/rails.rb +0 -70
  64. data/lib/bugsnag/rails/action_controller_rescue.rb +0 -74
  65. data/lib/bugsnag/shoryuken.rb +0 -41
  66. data/lib/bugsnag/tasks/bugsnag.cap +0 -48
  67. data/rails/init.rb +0 -7
@@ -1,10 +1,19 @@
1
1
  module Bugsnag
2
2
  module Delivery
3
3
  class << self
4
+ # Add a delivery method to the list of supported methods. Any registered
5
+ # method can then be used by name in Configuration.
6
+ #
7
+ # require 'bugsnag'
8
+ # Bugsnag::Delivery.register(:my_delivery_queue, MyDeliveryQueue)
9
+ # Bugsnag.configure do |config|
10
+ # config.delivery_method = :my_delivery_queue
11
+ # end
4
12
  def register(name, delivery_method)
5
13
  delivery_methods[name.to_sym] = delivery_method
6
14
  end
7
15
 
16
+ # Reference a delivery method by name
8
17
  def [](name)
9
18
  delivery_methods[name.to_sym]
10
19
  end
@@ -10,13 +10,13 @@ module Bugsnag
10
10
  def deliver(url, body, configuration)
11
11
  begin
12
12
  response = request(url, body, configuration)
13
- Bugsnag.debug("Notification to #{url} finished, response was #{response.code}, payload was #{body}")
13
+ configuration.debug("Notification to #{url} finished, response was #{response.code}, payload was #{body}")
14
14
  rescue StandardError => e
15
15
  # KLUDGE: Since we don't re-raise http exceptions, this breaks rspec
16
16
  raise if e.class.to_s == "RSpec::Expectations::ExpectationNotMetError"
17
17
 
18
- Bugsnag.warn("Notification to #{url} failed, #{e.inspect}")
19
- Bugsnag.warn(e.backtrace)
18
+ configuration.warn("Notification to #{url} failed, #{e.inspect}")
19
+ configuration.warn(e.backtrace)
20
20
  end
21
21
  end
22
22
 
@@ -36,8 +36,6 @@ module Bugsnag
36
36
 
37
37
  if uri.scheme == "https"
38
38
  http.use_ssl = true
39
- # the default in 1.9+, but required for 1.8
40
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
41
39
  http.ca_file = configuration.ca_file if configuration.ca_file
42
40
  end
43
41
 
@@ -9,10 +9,12 @@ module Bugsnag
9
9
 
10
10
  class << self
11
11
  def deliver(url, body, configuration)
12
+ @configuration = configuration
13
+
12
14
  start_once!
13
15
 
14
16
  if @queue.length > MAX_OUTSTANDING_REQUESTS
15
- Bugsnag.warn("Dropping notification, #{@queue.length} outstanding requests")
17
+ @configuration.warn("Dropping notification, #{@queue.length} outstanding requests")
16
18
  return
17
19
  end
18
20
 
@@ -38,7 +40,7 @@ module Bugsnag
38
40
  end
39
41
 
40
42
  at_exit do
41
- Bugsnag.warn("Waiting for #{@queue.length} outstanding request(s)") unless @queue.empty?
43
+ @configuration.warn("Waiting for #{@queue.length} outstanding request(s)") unless @queue.empty?
42
44
  @queue.push STOP
43
45
  worker_thread.join
44
46
  end
@@ -1,12 +1,12 @@
1
1
  require 'uri'
2
- require 'set' unless defined?(Set)
3
- require 'json' unless defined?(JSON)
2
+ require 'set'
3
+ require 'json'
4
4
 
5
5
 
6
6
  module Bugsnag
7
7
  module Helpers
8
8
  MAX_STRING_LENGTH = 3072
9
- MAX_PAYLOAD_LENGTH = 128000
9
+ MAX_PAYLOAD_LENGTH = 256000
10
10
  MAX_ARRAY_LENGTH = 40
11
11
  RAW_DATA_TYPES = [Numeric, TrueClass, FalseClass]
12
12
 
@@ -23,16 +23,9 @@ module Bugsnag
23
23
  remove_metadata_from_events(reduced_value)
24
24
  end
25
25
 
26
- def self.flatten_meta_data(overrides)
27
- return nil unless overrides
26
+ private
28
27
 
29
- meta_data = overrides.delete(:meta_data)
30
- if meta_data.is_a?(Hash)
31
- overrides.merge(meta_data)
32
- else
33
- overrides
34
- end
35
- end
28
+ TRUNCATION_INFO = '[TRUNCATED]'
36
29
 
37
30
  # Check if a value is a raw type which should not be trimmed, truncated
38
31
  # or converted to a string
@@ -40,10 +33,6 @@ module Bugsnag
40
33
  RAW_DATA_TYPES.detect {|klass| value.is_a?(klass)} != nil
41
34
  end
42
35
 
43
- private
44
-
45
- TRUNCATION_INFO = '[TRUNCATED]'
46
-
47
36
  # Shorten array until it fits within the payload size limit when serialized
48
37
  def self.truncate_array(array)
49
38
  return [] unless array.respond_to?(:slice)
@@ -8,9 +8,12 @@ end
8
8
  unless defined? Delayed::Plugins::Bugsnag
9
9
  module Delayed
10
10
  module Plugins
11
+ class Bugsnag < Plugin
11
12
 
13
+ FRAMEWORK_ATTRIBUTES = {
14
+ :framework => "DelayedJob"
15
+ }
12
16
 
13
- class Bugsnag < Plugin
14
17
  module Notify
15
18
  def error(job, error)
16
19
  overrides = {
@@ -19,11 +22,9 @@ unless defined? Delayed::Plugins::Bugsnag
19
22
  :id => job.id,
20
23
  },
21
24
  :severity_reason => {
22
- :type => ::Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
23
- :attributes => {
24
- :framework => "DelayedJob"
25
- }
26
- }
25
+ :type => ::Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
26
+ :attributes => FRAMEWORK_ATTRIBUTES,
27
+ },
27
28
  }
28
29
  if job.respond_to?(:queue) && (queue = job.queue)
29
30
  overrides[:job][:queue] = queue
@@ -50,7 +51,14 @@ unless defined? Delayed::Plugins::Bugsnag
50
51
  overrides[:job][:payload] = p
51
52
  end
52
53
 
53
- ::Bugsnag.auto_notify(error, overrides)
54
+ ::Bugsnag.notify(error, true) do |report|
55
+ report.severity = "error"
56
+ report.severity_reason = {
57
+ :type => ::Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
58
+ :attributes => FRAMEWORK_ATTRIBUTES
59
+ }
60
+ report.meta_data.merge! overrides
61
+ end
54
62
 
55
63
  super if defined?(super)
56
64
  end
@@ -2,6 +2,11 @@ require 'mailman'
2
2
 
3
3
  module Bugsnag
4
4
  class Mailman
5
+
6
+ FRAMEWORK_ATTRIBUTES = {
7
+ :framework => "Mailman"
8
+ }
9
+
5
10
  def initialize
6
11
  Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Mailman)
7
12
  Bugsnag.configuration.app_type = "mailman"
@@ -9,23 +14,20 @@ module Bugsnag
9
14
 
10
15
  def call(mail)
11
16
  begin
12
-
13
- Bugsnag.set_request_data :mailman_msg, mail.to_s
14
-
17
+ Bugsnag.configuration.set_request_data :mailman_msg, mail.to_s
15
18
  yield
16
19
  rescue Exception => ex
17
20
  raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
18
- Bugsnag.auto_notify(ex, {
19
- :severity_reason => {
20
- :type => Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
21
- :attributes => {
22
- :framework => "Mailman"
23
- }
21
+ Bugsnag.notify(ex, true) do |report|
22
+ report.severity = "error"
23
+ report.severity_reason = {
24
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
25
+ :attributes => FRAMEWORK_ATTRIBUTES
24
26
  }
25
- })
27
+ end
26
28
  raise
27
29
  ensure
28
- Bugsnag.clear_request_data
30
+ Bugsnag.configuration.clear_request_data
29
31
  end
30
32
  end
31
33
  end
@@ -3,14 +3,7 @@ if defined?(::Que)
3
3
  begin
4
4
  job = job.dup # Make sure the original job object is not mutated.
5
5
 
6
- Bugsnag.auto_notify(error, {
7
- :severity_reason => {
8
- :type => Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
9
- :attributes => {
10
- :framework => "Que"
11
- }
12
- }
13
- }) do |notification|
6
+ Bugsnag.notify(error, true) do |report|
14
7
  job[:error_count] += 1
15
8
 
16
9
  # If the job was scheduled using ActiveJob then unwrap the job details for clarity:
@@ -25,11 +18,18 @@ if defined?(::Que)
25
18
  job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job)
26
19
  end
27
20
 
28
- notification.add_tab(:job, job)
21
+ report.add_tab(:job, job)
22
+ report.severity = 'error'
23
+ report.severity_reason = {
24
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
25
+ :attributes => {
26
+ :framework => 'Que'
27
+ }
28
+ }
29
29
  end
30
30
  rescue => e
31
31
  # Que supresses errors raised by its error handler to avoid killing the worker. Log them somewhere:
32
- Bugsnag.warn("Failed to notify Bugsnag of error in Que job (#{e.class}): #{e.message} \n#{e.backtrace[0..9].join("\n")}")
32
+ Bugsnag.configuration.warn("Failed to notify Bugsnag of error in Que job (#{e.class}): #{e.message} \n#{e.backtrace[0..9].join("\n")}")
33
33
  raise
34
34
  end
35
35
  end
@@ -41,4 +41,4 @@ if defined?(::Que)
41
41
  Bugsnag.configuration.app_type ||= "que"
42
42
  Que.error_handler = handler
43
43
  end
44
- end
44
+ end
@@ -1,11 +1,8 @@
1
1
  module Bugsnag
2
2
  class Rack
3
3
 
4
- SEVERITY_REASON = {
5
- :type => Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
6
- :attributes => {
7
- :framework => "Rack"
8
- }
4
+ FRAMEWORK_ATTRIBUTES = {
5
+ :framework => "Rack"
9
6
  }
10
7
 
11
8
  def initialize(app)
@@ -14,37 +11,41 @@ module Bugsnag
14
11
  # Configure bugsnag rack defaults
15
12
  Bugsnag.configure do |config|
16
13
  # Try to set the release_stage automatically if it hasn't already been set
17
- config.release_stage ||= release_stage
14
+ config.release_stage ||= ENV["RACK_ENV"] if ENV["RACK_ENV"]
18
15
 
19
16
  # Try to set the project_root if it hasn't already been set, or show a warning if we can't
20
17
  unless config.project_root && !config.project_root.to_s.empty?
21
18
  if defined?(settings)
22
19
  config.project_root = settings.root
23
20
  else
24
- Bugsnag.warn("You should set your app's project_root (see https://bugsnag.com/docs/notifiers/ruby#project_root).")
21
+ config.warn("You should set your app's project_root (see https://bugsnag.com/docs/notifiers/ruby#project_root).")
25
22
  end
26
23
  end
27
24
 
28
25
  # Hook up rack-based notification middlewares
29
26
  config.middleware.insert_before([Bugsnag::Middleware::Rails3Request,Bugsnag::Middleware::Callbacks], Bugsnag::Middleware::RackRequest) if defined?(::Rack)
30
27
  config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::WardenUser) if defined?(Warden)
31
- config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)
28
+ config.middleware.insert_before(Bugsnag::Middleware::Callbkacs, Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)
32
29
 
33
- Bugsnag.configuration.app_type ||= "rack"
30
+ config.app_type ||= "rack"
34
31
  end
35
32
  end
36
33
 
37
34
  def call(env)
38
35
  # Set the request data for bugsnag middleware to use
39
- Bugsnag.set_request_data(:rack_env, env)
36
+ Bugsnag.configuration.set_request_data(:rack_env, env)
40
37
 
41
38
  begin
42
39
  response = @app.call(env)
43
40
  rescue Exception => raised
44
41
  # Notify bugsnag of rack exceptions
45
- Bugsnag.auto_notify(raised, {
46
- :severity_reason => SEVERITY_REASON
47
- })
42
+ Bugsnag.notify(raised, true) do |report|
43
+ report.severity = "error"
44
+ report.severity_reason = {
45
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
46
+ :attributes => Bugsnag::Rack::FRAMEWORK_ATTRIBUTES
47
+ }
48
+ end
48
49
 
49
50
  # Re-raise the exception
50
51
  raise
@@ -52,21 +53,19 @@ module Bugsnag
52
53
 
53
54
  # Notify bugsnag of rack exceptions
54
55
  if env["rack.exception"]
55
- Bugsnag.auto_notify(env["rack.exception"], {
56
- :severity_reason => SEVERITY_REASON
57
- })
56
+ Bugsnag.notify(env["rack.exception"], true) do |report|
57
+ report.severity = "error"
58
+ report.severity_reason = {
59
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
60
+ :attributes => FRAMEWORK_ATTRIBUTES
61
+ }
62
+ end
58
63
  end
59
64
 
60
65
  response
61
66
  ensure
62
67
  # Clear per-request data after processing the each request
63
- Bugsnag.clear_request_data
64
- end
65
-
66
- private
67
-
68
- def release_stage
69
- ENV["BUGSNAG_RELEASE_STAGE"] || ENV["RACK_ENV"]
68
+ Bugsnag.configuration.clear_request_data
70
69
  end
71
70
  end
72
71
  end
@@ -1,6 +1,9 @@
1
1
  module Bugsnag::Rails
2
2
  module ActiveRecordRescue
3
3
  KINDS = [:commit, :rollback].freeze
4
+ FRAMEWORK_ATTRIBUTES = {
5
+ :framework => "Rails"
6
+ }
4
7
 
5
8
  def run_callbacks(kind, *args, &block)
6
9
  if KINDS.include?(kind)
@@ -8,14 +11,13 @@ module Bugsnag::Rails
8
11
  super
9
12
  rescue StandardError => exception
10
13
  # This exception will NOT be escalated, so notify it here.
11
- Bugsnag.auto_notify(exception, {
12
- :severity_reason => {
13
- :type => Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
14
- :attributes => {
15
- :framework => "Rails"
16
- }
14
+ Bugsnag.notify(exception, true) do |report|
15
+ report.severity = "error"
16
+ report.severity_reason = {
17
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
18
+ :attributes => FRAMEWORK_ATTRIBUTES
17
19
  }
18
- })
20
+ end
19
21
  raise
20
22
  end
21
23
  else
@@ -10,10 +10,6 @@ module Bugsnag::Rails
10
10
  _add_bugsnag_notify_callback(:before_callbacks, *methods, &block)
11
11
  end
12
12
 
13
- def after_bugsnag_notify(*methods, &block)
14
- _add_bugsnag_notify_callback(:after_callbacks, *methods, &block)
15
- end
16
-
17
13
  def _add_bugsnag_notify_callback(callback_key, *methods, &block)
18
14
  options = methods.last.is_a?(Hash) ? methods.pop : {}
19
15
 
@@ -40,10 +36,5 @@ module Bugsnag::Rails
40
36
  end
41
37
  end
42
38
  end
43
-
44
- private
45
- def notify_bugsnag(exception, custom_data=nil)
46
- Bugsnag.notify(exception, custom_data)
47
- end
48
39
  end
49
40
  end
@@ -7,8 +7,13 @@ require "bugsnag/middleware/rack_request"
7
7
 
8
8
  module Bugsnag
9
9
  class Railtie < Rails::Railtie
10
+
11
+ FRAMEWORK_ATTRIBUTES = {
12
+ :framework => "Rails"
13
+ }
14
+
10
15
  rake_tasks do
11
- require "bugsnag/rake"
16
+ require "bugsnag/integrations/rake"
12
17
  load "bugsnag/tasks/bugsnag.rake"
13
18
  end
14
19
 
@@ -17,14 +22,13 @@ module Bugsnag
17
22
  runner do
18
23
  at_exit do
19
24
  if $!
20
- Bugsnag.auto_notify($!, {
21
- :severity_reason => {
22
- :type => Bugsnag::Notification::UNHANDLED_EXCEPTION_MIDDLEWARE,
23
- :attributes => {
24
- :framework => "Rails"
25
- }
25
+ Bugsnag.notify($!, true) do |report|
26
+ report.severity = "error"
27
+ report.severity_reason = {
28
+ :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
29
+ :attributes => FRAMEWORK_ATTRIBUTES
26
30
  }
27
- })
31
+ end
28
32
  end
29
33
  end
30
34
  end
@@ -39,28 +43,27 @@ module Bugsnag
39
43
  config.middleware.insert_before Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::Rails3Request
40
44
  end
41
45
 
42
- # Auto-load configuration settings from config/bugsnag.yml if it exists
43
- config_file = ::Rails.root.join("config", "bugsnag.yml")
44
- config = YAML.load_file(config_file) if File.exist?(config_file)
45
- Bugsnag.configure(config[::Rails.env] ? config[::Rails.env] : config) if config
46
-
47
- ActiveSupport.on_load(:action_controller) do
48
- require "bugsnag/rails/controller_methods"
49
- include Bugsnag::Rails::ControllerMethods
46
+ if defined?(::ActionController::Base)
47
+ require "bugsnag/integrations/rails/controller_methods"
48
+ ::ActionController::Base.send(:include, Bugsnag::Rails::ControllerMethods)
49
+ end
50
+ if defined?(ActionController::API)
51
+ require "bugsnag/integrations/rails/controller_methods"
52
+ ActionController::API.send(:include, Bugsnag::Rails::ControllerMethods)
50
53
  end
51
- ActiveSupport.on_load(:active_record) do
52
- require "bugsnag/rails/active_record_rescue"
53
- include Bugsnag::Rails::ActiveRecordRescue
54
+ if defined?(ActiveRecord::Base)
55
+ require "bugsnag/integrations/rails/active_record_rescue"
56
+ ActiveRecord::Base.send(:include, Bugsnag::Rails::ActiveRecordRescue)
54
57
  end
55
58
 
56
59
  Bugsnag.configuration.app_type = "rails"
57
60
  end
58
61
 
59
- # Configure params_filters after initialization, so that rails initializers
62
+ # Configure meta_data_filters after initialization, so that rails initializers
60
63
  # may set filter_parameters which will be picked up by Bugsnag.
61
64
  config.after_initialize do
62
65
  Bugsnag.configure do |config|
63
- config.params_filters += ::Rails.configuration.filter_parameters.map do |filter|
66
+ config.meta_data_filters += ::Rails.configuration.filter_parameters.map do |filter|
64
67
  case filter
65
68
  when String, Symbol
66
69
  /\A#{filter}\z/