bugsnag-maglev- 2.8.12

Sign up to get free protection for your applications and to get access to all the features.
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