bugsnag-maglev- 2.8.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +52 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +15 -0
  6. data/CHANGELOG.md +425 -0
  7. data/CONTRIBUTING.md +43 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +804 -0
  11. data/Rakefile +29 -0
  12. data/VERSION +1 -0
  13. data/bugsnag.gemspec +32 -0
  14. data/lib/bugsnag.rb +129 -0
  15. data/lib/bugsnag/capistrano.rb +7 -0
  16. data/lib/bugsnag/capistrano2.rb +32 -0
  17. data/lib/bugsnag/configuration.rb +129 -0
  18. data/lib/bugsnag/delay/resque.rb +21 -0
  19. data/lib/bugsnag/delayed_job.rb +57 -0
  20. data/lib/bugsnag/delivery.rb +18 -0
  21. data/lib/bugsnag/delivery/synchronous.rb +51 -0
  22. data/lib/bugsnag/delivery/thread_queue.rb +53 -0
  23. data/lib/bugsnag/deploy.rb +35 -0
  24. data/lib/bugsnag/helpers.rb +127 -0
  25. data/lib/bugsnag/mailman.rb +28 -0
  26. data/lib/bugsnag/meta_data.rb +7 -0
  27. data/lib/bugsnag/middleware/callbacks.rb +19 -0
  28. data/lib/bugsnag/middleware/mailman.rb +13 -0
  29. data/lib/bugsnag/middleware/rack_request.rb +72 -0
  30. data/lib/bugsnag/middleware/rails2_request.rb +52 -0
  31. data/lib/bugsnag/middleware/rails3_request.rb +42 -0
  32. data/lib/bugsnag/middleware/rake.rb +23 -0
  33. data/lib/bugsnag/middleware/sidekiq.rb +13 -0
  34. data/lib/bugsnag/middleware/warden_user.rb +39 -0
  35. data/lib/bugsnag/middleware_stack.rb +98 -0
  36. data/lib/bugsnag/notification.rb +452 -0
  37. data/lib/bugsnag/rack.rb +53 -0
  38. data/lib/bugsnag/rails.rb +66 -0
  39. data/lib/bugsnag/rails/action_controller_rescue.rb +62 -0
  40. data/lib/bugsnag/rails/active_record_rescue.rb +20 -0
  41. data/lib/bugsnag/rails/controller_methods.rb +44 -0
  42. data/lib/bugsnag/railtie.rb +78 -0
  43. data/lib/bugsnag/rake.rb +25 -0
  44. data/lib/bugsnag/resque.rb +40 -0
  45. data/lib/bugsnag/sidekiq.rb +38 -0
  46. data/lib/bugsnag/tasks.rb +3 -0
  47. data/lib/bugsnag/tasks/bugsnag.cap +48 -0
  48. data/lib/bugsnag/tasks/bugsnag.rake +89 -0
  49. data/lib/bugsnag/version.rb +3 -0
  50. data/lib/generators/bugsnag/bugsnag_generator.rb +24 -0
  51. data/rails/init.rb +3 -0
  52. data/spec/code_spec.rb +86 -0
  53. data/spec/fixtures/crashes/end_of_file.rb +9 -0
  54. data/spec/fixtures/crashes/short_file.rb +1 -0
  55. data/spec/fixtures/crashes/start_of_file.rb +9 -0
  56. data/spec/fixtures/middleware/internal_info_setter.rb +11 -0
  57. data/spec/fixtures/middleware/public_info_setter.rb +11 -0
  58. data/spec/fixtures/tasks/Rakefile +15 -0
  59. data/spec/helper_spec.rb +144 -0
  60. data/spec/integration_spec.rb +110 -0
  61. data/spec/middleware_spec.rb +181 -0
  62. data/spec/notification_spec.rb +822 -0
  63. data/spec/rack_spec.rb +56 -0
  64. data/spec/spec_helper.rb +53 -0
  65. metadata +198 -0
@@ -0,0 +1,53 @@
1
+ module Bugsnag
2
+ class Rack
3
+ def initialize(app)
4
+ @app = app
5
+
6
+ # Configure bugsnag rack defaults
7
+ Bugsnag.configure do |config|
8
+ # Try to set the release_stage automatically if it hasn't already been set
9
+ config.release_stage ||= ENV["RACK_ENV"] if ENV["RACK_ENV"]
10
+
11
+ # Try to set the project_root if it hasn't already been set, or show a warning if we can't
12
+ unless config.project_root && !config.project_root.to_s.empty?
13
+ if defined?(settings)
14
+ config.project_root = settings.root
15
+ else
16
+ Bugsnag.warn("You should set your app's project_root (see https://bugsnag.com/docs/notifiers/ruby#project_root).")
17
+ end
18
+ end
19
+
20
+ # Hook up rack-based notification middlewares
21
+ config.middleware.insert_before([Bugsnag::Middleware::Rails3Request,Bugsnag::Middleware::Callbacks], Bugsnag::Middleware::RackRequest) if defined?(::Rack)
22
+ config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::WardenUser) if defined?(Warden)
23
+
24
+ Bugsnag.configuration.app_type ||= "rack"
25
+ end
26
+ end
27
+
28
+ def call(env)
29
+ # Set the request data for bugsnag middleware to use
30
+ Bugsnag.set_request_data(:rack_env, env)
31
+
32
+ begin
33
+ response = @app.call(env)
34
+ rescue Exception => raised
35
+ # Notify bugsnag of rack exceptions
36
+ Bugsnag.auto_notify(raised)
37
+
38
+ # Re-raise the exception
39
+ raise
40
+ end
41
+
42
+ # Notify bugsnag of rack exceptions
43
+ if env["rack.exception"]
44
+ Bugsnag.auto_notify(env["rack.exception"])
45
+ end
46
+
47
+ response
48
+ ensure
49
+ # Clear per-request data after processing the each request
50
+ Bugsnag.clear_request_data
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,66 @@
1
+ # Rails 2.x hooks
2
+ # For Rails 3+ hooks, see railtie.rb
3
+
4
+ require "bugsnag"
5
+ require "bugsnag/rails/controller_methods"
6
+ require "bugsnag/rails/action_controller_rescue"
7
+ require "bugsnag/rails/active_record_rescue"
8
+ require "bugsnag/middleware/rails2_request"
9
+ require "bugsnag/middleware/callbacks"
10
+
11
+ module Bugsnag
12
+ module Rails
13
+ def self.initialize
14
+ if defined?(ActionController::Base)
15
+ ActionController::Base.send(:include, Bugsnag::Rails::ActionControllerRescue)
16
+ ActionController::Base.send(:include, Bugsnag::Rails::ControllerMethods)
17
+ end
18
+ if defined?(ActiveRecord::Base) && Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("4.3")
19
+ unless ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks) && ActiveRecord::Base.raise_in_transactional_callbacks
20
+ ActiveRecord::Base.send(:include, Bugsnag::Rails::ActiveRecordRescue)
21
+ end
22
+ end
23
+
24
+ Bugsnag.configure do |config|
25
+ config.logger ||= rails_logger
26
+ config.release_stage = rails_env if rails_env
27
+ config.project_root = rails_root if rails_root
28
+
29
+ config.middleware.insert_before(Bugsnag::Middleware::Callbacks,Bugsnag::Middleware::Rails2Request)
30
+ end
31
+
32
+ # Auto-load configuration settings from config/bugsnag.yml if it exists
33
+ config_file = File.join(rails_root, "config", "bugsnag.yml")
34
+ config = YAML.load_file(config_file) if File.exists?(config_file)
35
+ Bugsnag.configure(config[rails_env] ? config[rails_env] : config) if config
36
+
37
+ Bugsnag.configuration.app_type = "rails"
38
+ end
39
+
40
+ def self.rails_logger
41
+ if defined?(::Rails.logger)
42
+ rails_logger = ::Rails.logger
43
+ elsif defined?(RAILS_DEFAULT_LOGGER)
44
+ rails_logger = RAILS_DEFAULT_LOGGER
45
+ end
46
+ end
47
+
48
+ def self.rails_env
49
+ if defined?(::Rails.env)
50
+ ::Rails.env
51
+ elsif defined?(RAILS_ENV)
52
+ RAILS_ENV
53
+ end
54
+ end
55
+
56
+ def self.rails_root
57
+ if defined?(::Rails.root)
58
+ ::Rails.root
59
+ elsif defined?(RAILS_ROOT)
60
+ RAILS_ROOT
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ Bugsnag::Rails.initialize
@@ -0,0 +1,62 @@
1
+ # Rails 2.x only
2
+ module Bugsnag::Rails
3
+ module ActionControllerRescue
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+
7
+ # Hook into rails exception rescue stack
8
+ base.send(:alias_method, :rescue_action_in_public_without_bugsnag, :rescue_action_in_public)
9
+ base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_bugsnag)
10
+
11
+ base.send(:alias_method, :rescue_action_locally_without_bugsnag, :rescue_action_locally)
12
+ base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_bugsnag)
13
+
14
+ # Run filters on requests to capture request data
15
+ base.send(:prepend_before_filter, :set_bugsnag_request_data)
16
+ end
17
+
18
+ private
19
+ def set_bugsnag_request_data
20
+ Bugsnag.clear_request_data
21
+ Bugsnag.set_request_data(:rails2_request, request)
22
+ end
23
+
24
+ def rescue_action_in_public_with_bugsnag(exception)
25
+ Bugsnag.auto_notify(exception)
26
+
27
+ rescue_action_in_public_without_bugsnag(exception)
28
+ end
29
+
30
+ def rescue_action_locally_with_bugsnag(exception)
31
+ Bugsnag.auto_notify(exception)
32
+
33
+ rescue_action_locally_without_bugsnag(exception)
34
+ end
35
+
36
+ module ClassMethods
37
+
38
+ def self.extended(base)
39
+ base.singleton_class.class_eval do
40
+ alias_method_chain :filter_parameter_logging, :bugsnag
41
+ end
42
+ end
43
+
44
+ # Rails 2 does parameter filtering via a controller configuration method
45
+ # that dynamically defines a method on the controller, so the configured
46
+ # parameters aren't easily accessible. Intercept these parameters as
47
+ # they're configured so that the Bugsnag configuration can take them
48
+ # into account.
49
+ #
50
+ def filter_parameter_logging_with_bugsnag(*filter_words, &block)
51
+ if filter_words.length > 0
52
+ Bugsnag.configure do |config|
53
+ # Use the same regular expression that Rails parameter filtering uses.
54
+ config.params_filters << Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true)
55
+ end
56
+ end
57
+ filter_parameter_logging_without_bugsnag(*filter_words, &block)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ module Bugsnag::Rails
2
+ module ActiveRecordRescue
3
+ KINDS = [:commit, :rollback].freeze
4
+
5
+ def run_callbacks(kind, *args, &block)
6
+ if KINDS.include?(kind)
7
+ begin
8
+ super
9
+ rescue StandardError => exception
10
+ # This exception will NOT be escalated, so notify it here.
11
+ Bugsnag.auto_notify(exception)
12
+ raise
13
+ end
14
+ else
15
+ # Let the post process handle the exception
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ module Bugsnag::Rails
2
+ module ControllerMethods
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ private
9
+ def before_bugsnag_notify(*methods, &block)
10
+ _add_bugsnag_notify_callback(:before_callbacks, *methods, &block)
11
+ end
12
+
13
+ def after_bugsnag_notify(*methods, &block)
14
+ _add_bugsnag_notify_callback(:after_callbacks, *methods, &block)
15
+ end
16
+
17
+ def _add_bugsnag_notify_callback(callback_key, *methods, &block)
18
+ options = methods.last.is_a?(Hash) ? methods.pop : {}
19
+
20
+ before_filter(options) do |controller|
21
+ request_data = Bugsnag.configuration.request_data
22
+ request_data[callback_key] ||= []
23
+
24
+ # Set up "method symbol" callbacks
25
+ methods.each do |method_symbol|
26
+ request_data[callback_key] << lambda { |notification|
27
+ controller.send(method_symbol, notification)
28
+ }
29
+ end
30
+
31
+ # Set up "block" callbacks
32
+ request_data[callback_key] << lambda { |notification|
33
+ controller.instance_exec(notification, &block)
34
+ } if block_given?
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+ def notify_bugsnag(exception, custom_data=nil)
41
+ Bugsnag.notify(exception, custom_data)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,78 @@
1
+ # Rails 3.x hooks
2
+
3
+ require "rails"
4
+ require "bugsnag"
5
+ require "bugsnag/middleware/rails3_request"
6
+ require "bugsnag/middleware/rack_request"
7
+
8
+ module Bugsnag
9
+ class Railtie < Rails::Railtie
10
+ rake_tasks do
11
+ require "bugsnag/rake"
12
+ load "bugsnag/tasks/bugsnag.rake"
13
+ end
14
+
15
+ # send notifications if a command fails in a 'rails runner' call
16
+ if self.respond_to? :runner
17
+ runner do
18
+ at_exit do
19
+ if $!
20
+ Bugsnag.auto_notify($!)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ config.before_initialize do
27
+ # Configure bugsnag rails defaults
28
+ Bugsnag.configure do |config|
29
+ config.logger = ::Rails.logger
30
+ config.release_stage = ::Rails.env.to_s
31
+ config.project_root = ::Rails.root.to_s
32
+ config.middleware.insert_before Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::Rails3Request
33
+ end
34
+
35
+ # Auto-load configuration settings from config/bugsnag.yml if it exists
36
+ config_file = ::Rails.root.join("config", "bugsnag.yml")
37
+ config = YAML.load_file(config_file) if File.exists?(config_file)
38
+ Bugsnag.configure(config[::Rails.env] ? config[::Rails.env] : config) if config
39
+
40
+ if defined?(::ActionController::Base)
41
+ require "bugsnag/rails/controller_methods"
42
+ ::ActionController::Base.send(:include, Bugsnag::Rails::ControllerMethods)
43
+ end
44
+ if defined?(ActionController::API)
45
+ ActionController::API.send(:include, Bugsnag::Rails::ControllerMethods)
46
+ end
47
+ if defined?(ActiveRecord::Base)
48
+ require "bugsnag/rails/active_record_rescue"
49
+ ActiveRecord::Base.send(:include, Bugsnag::Rails::ActiveRecordRescue)
50
+ end
51
+
52
+ Bugsnag.configuration.app_type = "rails"
53
+ end
54
+
55
+ # Configure params_filters after initialization, so that rails initializers
56
+ # may set filter_parameters which will be picked up by Bugsnag.
57
+ config.after_initialize do
58
+ Bugsnag.configure do |config|
59
+ config.params_filters += ::Rails.configuration.filter_parameters.map do |filter|
60
+ case filter
61
+ when String, Symbol
62
+ /\A#{filter}\z/
63
+ else
64
+ filter
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ initializer "bugsnag.use_rack_middleware" do |app|
71
+ begin
72
+ app.config.middleware.insert_after ActionDispatch::DebugExceptions, "Bugsnag::Rack"
73
+ rescue
74
+ app.config.middleware.use "Bugsnag::Rack"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,25 @@
1
+ require 'bugsnag'
2
+
3
+ Rake::TaskManager.record_task_metadata = true
4
+
5
+ class Rake::Task
6
+
7
+ def execute_with_bugsnag(args=nil)
8
+ Bugsnag.configuration.app_type = "rake"
9
+ old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
10
+ Bugsnag.set_request_data :bugsnag_running_task, self
11
+
12
+ execute_without_bugsnag(args)
13
+
14
+ rescue Exception => ex
15
+ Bugsnag.auto_notify(ex)
16
+ raise
17
+ ensure
18
+ Bugsnag.set_request_data :bugsnag_running_task, old_task
19
+ end
20
+
21
+ alias_method :execute_without_bugsnag, :execute
22
+ alias_method :execute, :execute_with_bugsnag
23
+ end
24
+
25
+ Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Rake)
@@ -0,0 +1,40 @@
1
+ require "resque"
2
+ require "resque/failure/multiple"
3
+
4
+ module Bugsnag
5
+ class Resque < ::Resque::Failure::Base
6
+ def self.configure(&block)
7
+ add_failure_backend
8
+ Bugsnag.configure(&block)
9
+ end
10
+
11
+ def self.add_failure_backend
12
+ return if ::Resque::Failure.backend == self
13
+
14
+ # Ensure resque is using a "Multiple" failure backend
15
+ unless ::Resque::Failure.backend < ::Resque::Failure::Multiple
16
+ original_backend = ::Resque::Failure.backend
17
+ ::Resque::Failure.backend = ::Resque::Failure::Multiple
18
+ ::Resque::Failure.backend.classes ||= []
19
+ ::Resque::Failure.backend.classes << original_backend
20
+ end
21
+
22
+ # Add Bugsnag failure backend
23
+ unless ::Resque::Failure.backend.classes.include?(self)
24
+ ::Resque::Failure.backend.classes << self
25
+ end
26
+ end
27
+
28
+ def save
29
+ Bugsnag.auto_notify(exception, {:context => "resque##{queue}", :payload => payload, :delivery_method => :synchronous})
30
+ end
31
+ end
32
+ end
33
+
34
+ # For backwards compatibility
35
+ Resque::Failure::Bugsnag = Bugsnag::Resque
36
+
37
+ # Auto-load the failure backend
38
+ Bugsnag::Resque.add_failure_backend
39
+
40
+ Bugsnag.configuration.app_type = "resque"
@@ -0,0 +1,38 @@
1
+ require 'sidekiq'
2
+
3
+ module Bugsnag
4
+ class Sidekiq
5
+ def call(worker, msg, queue)
6
+ begin
7
+
8
+ # store msg/queue in thread local state to be read by Bugsnag::Middleware::Sidekiq
9
+ Bugsnag.set_request_data :sidekiq, { :msg => msg, :queue => queue }
10
+
11
+ yield
12
+ rescue Exception => ex
13
+ raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
14
+ Bugsnag.auto_notify(ex)
15
+ raise
16
+ ensure
17
+ Bugsnag.clear_request_data
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ if ::Sidekiq::VERSION < '3'
24
+ ::Sidekiq.configure_server do |config|
25
+ config.server_middleware do |chain|
26
+ chain.add ::Bugsnag::Sidekiq
27
+ end
28
+ end
29
+ else
30
+ ::Sidekiq.configure_server do |config|
31
+ config.error_handlers << lambda do |ex, ctx|
32
+ Bugsnag.auto_notify(ex, :sidekiq => ctx, :context => "sidekiq##{ctx['queue']}")
33
+ end
34
+ end
35
+ end
36
+
37
+ Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Sidekiq)
38
+ Bugsnag.configuration.app_type = "sidekiq"
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].each do |task|
2
+ load task
3
+ end
@@ -0,0 +1,48 @@
1
+ namespace :load do
2
+
3
+ task :defaults do
4
+
5
+ set :bugsnag_default_hooks, ->{ true }
6
+
7
+ end
8
+
9
+ end
10
+
11
+ namespace :deploy do
12
+
13
+ before :starting, :bugsnag_hooks do
14
+ invoke 'bugsnag:add_default_hooks' if fetch(:bugsnag_default_hooks)
15
+ end
16
+
17
+ end
18
+
19
+ namespace :bugsnag do
20
+
21
+ task :add_default_hooks do
22
+ after 'deploy:published', 'bugsnag:deploy'
23
+ end
24
+
25
+ desc 'Notify Bugsnag that new production code has been deployed'
26
+ task :deploy do
27
+ run_locally do
28
+ begin
29
+ Bugsnag::Deploy.notify({
30
+ :api_key => fetch(:bugsnag_api_key, ENV["BUGSNAG_API_KEY"]),
31
+ :release_stage => fetch(:bugsnag_env) || fetch(:rails_env) || fetch(:stage) || ENV["BUGSNAG_RELEASE_STAGE"] || "production",
32
+ :revision => fetch(:current_revision, ENV["BUGSNAG_REVISION"]),
33
+ :repository => fetch(:repo_url, ENV["BUGSNAG_REPOSITORY"]),
34
+ :branch => fetch(:branch, ENV["BUGSNAG_BRANCH"]),
35
+ :app_version => fetch(:app_version, ENV["BUGSNAG_APP_VERSION"]),
36
+ :endpoint => fetch(:bugsnag_endpoint, Bugsnag::Configuration::DEFAULT_ENDPOINT),
37
+ :use_ssl => fetch(:bugsnag_use_ssl, true)
38
+ })
39
+ rescue
40
+ error "Bugsnag deploy notification failed, #{$!.inspect}"
41
+ end
42
+
43
+ info 'Bugsnag deploy notification complete.'
44
+ end
45
+ end
46
+
47
+ end
48
+ # vi:ft=ruby