dfg-airbrake 5.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake.rb +57 -0
  3. data/lib/airbrake/capistrano/tasks.rb +65 -0
  4. data/lib/airbrake/delayed_job/plugin1.rb +52 -0
  5. data/lib/airbrake/rack/middleware.rb +59 -0
  6. data/lib/airbrake/rack/notice_builder.rb +125 -0
  7. data/lib/airbrake/rack/user.rb +61 -0
  8. data/lib/airbrake/rails/action_controller.rb +37 -0
  9. data/lib/airbrake/rails/active_job.rb +35 -0
  10. data/lib/airbrake/rails/active_record.rb +36 -0
  11. data/lib/airbrake/rails/railtie.rb +79 -0
  12. data/lib/airbrake/rake/task_ext.rb +66 -0
  13. data/lib/airbrake/rake/tasks.rb +118 -0
  14. data/lib/airbrake/resque/failure.rb +19 -0
  15. data/lib/airbrake/sidekiq/error_handler.rb +35 -0
  16. data/lib/airbrake/version.rb +6 -0
  17. data/lib/generators/airbrake_generator.rb +25 -0
  18. data/lib/generators/airbrake_initializer.rb.erb +68 -0
  19. data/spec/airbrake_spec.rb +17 -0
  20. data/spec/apps/rack/dummy_app.rb +17 -0
  21. data/spec/apps/rails/dummy_app.rb +156 -0
  22. data/spec/apps/rails/dummy_task.rake +20 -0
  23. data/spec/apps/sinatra/composite_app/sinatra_app1.rb +11 -0
  24. data/spec/apps/sinatra/composite_app/sinatra_app2.rb +11 -0
  25. data/spec/apps/sinatra/dummy_app.rb +12 -0
  26. data/spec/integration/rack/rack_spec.rb +17 -0
  27. data/spec/integration/rails/rails_spec.rb +216 -0
  28. data/spec/integration/rails/rake_spec.rb +160 -0
  29. data/spec/integration/shared_examples/rack_examples.rb +126 -0
  30. data/spec/integration/sinatra/sinatra_spec.rb +77 -0
  31. data/spec/spec_helper.rb +116 -0
  32. data/spec/unit/rack/middleware_spec.rb +136 -0
  33. data/spec/unit/rack/notice_builder_spec.rb +157 -0
  34. data/spec/unit/rack/user_spec.rb +172 -0
  35. data/spec/unit/rake/tasks_spec.rb +67 -0
  36. data/spec/unit/sidekiq/error_handler_spec.rb +33 -0
  37. metadata +247 -0
@@ -0,0 +1,35 @@
1
+ module Airbrake
2
+ module Rails
3
+ ##
4
+ # Enables support for exceptions occurring in ActiveJob jobs.
5
+ module ActiveJob
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ if ::Rails.application.config.respond_to?(:active_job)
10
+ active_job_cfg = ::Rails.application.config.active_job
11
+ is_resque_adapter = (active_job_cfg.queue_adapter == :resque)
12
+ end
13
+
14
+ rescue_from(Exception) do |exception|
15
+ if (notice = Airbrake.build_notice(exception))
16
+ notice[:context][:component] = 'active_job'
17
+ notice[:context][:action] = self.class.name
18
+
19
+ notice[:params] = serialize
20
+
21
+ # We special case Resque because it kills our workers by forking, so
22
+ # we use synchronous delivery instead.
23
+ if is_resque_adapter
24
+ Airbrake.notify_sync(notice)
25
+ else
26
+ Airbrake.notify(notice)
27
+ end
28
+ end
29
+
30
+ raise exception
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ module Airbrake
2
+ module Rails
3
+ ##
4
+ # Rails <4.2 has a bug with regard to swallowing exceptions in the
5
+ # +after_commit+ and the +after_rollback+ hooks: it doesn't bubble up
6
+ # exceptions from there.
7
+ #
8
+ # This module makes it possible to report exceptions occurring there.
9
+ #
10
+ # @see https://github.com/rails/rails/pull/14488 Detailed description of the
11
+ # bug and the fix
12
+ # @see https://goo.gl/348lor Rails 4.2+ implementation (fixed)
13
+ # @see https://goo.gl/ddFNg7 Rails <4.2 implementation (bugged)
14
+ module ActiveRecord
15
+ ##
16
+ # Patches default +run_callbacks+ with our version, which is capable of
17
+ # notifying about exceptions.
18
+ #
19
+ # rubocop:disable Lint/RescueException
20
+ def run_callbacks(kind, *args, &block)
21
+ # Let the post process handle the exception if it's not a bugged hook.
22
+ return super unless [:commit, :rollback].include?(kind)
23
+
24
+ # Handle the exception ourselves. The 'ex' exception won't be
25
+ # propagated, therefore we must notify it here.
26
+ begin
27
+ super
28
+ rescue Exception => ex
29
+ Airbrake.notify(ex)
30
+ raise ex
31
+ end
32
+ end
33
+ # rubocop:enable Lint/RescueException
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,79 @@
1
+ module Airbrake
2
+ module Rails
3
+ ##
4
+ # This railtie works for any Rails application that supports railties (Rails
5
+ # 3.2+ apps). It makes Airbrake Ruby work with Rails and report errors
6
+ # occurring in the application automatically.
7
+ class Railtie < ::Rails::Railtie
8
+ initializer('airbrake.middleware') do |app|
9
+ # Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is
10
+ # responsible for logging exceptions and showing a debugging page in
11
+ # case the request is local. We want to insert our middleware after
12
+ # DebugExceptions, so we don't notify Airbrake about local requests.
13
+
14
+ if ::Rails.version.start_with?('5.')
15
+ # Avoid the warning about deprecated strings.
16
+ # Insert after DebugExceptions, since ConnectionManagement doesn't
17
+ # exist in Rails 5 anymore.
18
+ app.config.middleware.insert_after(
19
+ ActionDispatch::DebugExceptions,
20
+ Airbrake::Rack::Middleware
21
+ )
22
+ elsif defined?(ActiveRecord)
23
+ # Insert after ConnectionManagement to avoid DB connection leakage:
24
+ # https://github.com/airbrake/airbrake/pull/568
25
+ app.config.middleware.insert_after(
26
+ ActiveRecord::ConnectionAdapters::ConnectionManagement,
27
+ 'Airbrake::Rack::Middleware'
28
+ )
29
+ else
30
+ # Insert after DebugExceptions for apps without ActiveRecord.
31
+ app.config.middleware.insert_after(
32
+ ActionDispatch::DebugExceptions,
33
+ 'Airbrake::Rack::Middleware'
34
+ )
35
+ end
36
+ end
37
+
38
+ rake_tasks do
39
+ # Report exceptions occurring in Rake tasks.
40
+ require 'airbrake/rake/task_ext'
41
+
42
+ # Defines tasks such as `airbrake:test` & `airbrake:deploy`.
43
+ require 'airbrake/rake/tasks'
44
+ end
45
+
46
+ initializer('airbrake.action_controller') do
47
+ ActiveSupport.on_load(:action_controller) do
48
+ # Patches ActionController with methods that allow us to retrieve
49
+ # interesting request data. Appends that information to notices.
50
+ require 'airbrake/rails/action_controller'
51
+ include Airbrake::Rails::ActionController
52
+ end
53
+ end
54
+
55
+ initializer('airbrake.active_record') do
56
+ ActiveSupport.on_load(:active_record) do
57
+ # Reports exceptions occurring in some bugged ActiveRecord callbacks.
58
+ # Applicable only to the versions of Rails lower than 4.2.
59
+ require 'airbrake/rails/active_record'
60
+ include Airbrake::Rails::ActiveRecord
61
+ end
62
+ end
63
+
64
+ initializer('airbrake.active_job') do
65
+ ActiveSupport.on_load(:active_job) do
66
+ # Reports exceptions occurring in ActiveJob jobs.
67
+ require 'airbrake/rails/active_job'
68
+ include Airbrake::Rails::ActiveJob
69
+ end
70
+ end
71
+
72
+ runner do
73
+ at_exit do
74
+ Airbrake.notify_sync($ERROR_INFO) if $ERROR_INFO
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,66 @@
1
+ # This is not bulletproof, but if this file is executed before a task
2
+ # definition, we can grab tasks descriptions and locations.
3
+ # See: https://goo.gl/ksn6PE
4
+ Rake::TaskManager.record_task_metadata = true
5
+
6
+ module Rake
7
+ ##
8
+ # Redefine +Rake::Task#execute+, so it can report errors to Airbrake.
9
+ class Task
10
+ # Store the original method to use it later.
11
+ alias execute_without_airbrake execute
12
+
13
+ ##
14
+ # A wrapper around the original +#execute+, that catches all errors and
15
+ # notifies Airbrake.
16
+ #
17
+ # rubocop:disable Lint/RescueException
18
+ def execute(args = nil)
19
+ execute_without_airbrake(args)
20
+ rescue Exception => ex
21
+ notify_airbrake(ex, args)
22
+ raise ex
23
+ end
24
+ # rubocop:enable Lint/RescueException
25
+
26
+ private
27
+
28
+ def notify_airbrake(exception, args)
29
+ return unless (notice = Airbrake.build_notice(exception))
30
+
31
+ notice[:context][:component] = 'rake'
32
+ notice[:context][:action] = name
33
+ notice[:params] = {
34
+ rake_task: task_info,
35
+ execute_args: args,
36
+ argv: ARGV.join(' ')
37
+ }
38
+
39
+ Airbrake.notify_sync(notice)
40
+ end
41
+
42
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
43
+ def task_info
44
+ info = {}
45
+
46
+ info[:name] = name
47
+ info[:timestamp] = timestamp.to_s
48
+ info[:investigation] = investigation
49
+
50
+ info[:full_comment] = full_comment if full_comment
51
+ info[:arg_names] = arg_names if arg_names.any?
52
+ info[:arg_description] = arg_description if arg_description
53
+ info[:locations] = locations if locations.any?
54
+ info[:sources] = sources if sources.any?
55
+
56
+ if prerequisite_tasks.any?
57
+ info[:prerequisite_tasks] = prerequisite_tasks.map do |p|
58
+ p.__send__(:task_info)
59
+ end
60
+ end
61
+
62
+ info
63
+ end
64
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
65
+ end
66
+ end
@@ -0,0 +1,118 @@
1
+ namespace :airbrake do
2
+ desc 'Verify your gem installation by sending a test exception'
3
+ task test: :environment do
4
+ require 'pp'
5
+
6
+ begin
7
+ raise StandardError, 'Exception from the test Rake task'
8
+ rescue => ex
9
+ response = Airbrake.notify_sync(ex)
10
+ end
11
+
12
+ notifiers = Airbrake.instance_variable_get(:@notifiers).map do |name, notif|
13
+ cfg = notif.instance_variable_get(:@config)
14
+ filters = notif.instance_variable_get(:@filter_chain)
15
+ "#{name}:\n " + [cfg, filters].pretty_inspect
16
+ end.join("\n")
17
+
18
+ if !response
19
+ puts <<-NORESPONSE.gsub(/^\s+\|/, '')
20
+ |Couldn't send a test exception. There are two reasons for this:
21
+ |
22
+ |1. Airbrake ignored this exception due to misconfigured filters
23
+ |2. Airbrake was configured to ignore the '#{Rails.env}' environment.
24
+ | To fix this try one of the following:
25
+ | * specify another environment via RAILS_ENV
26
+ | * temporarily unignore the '#{Rails.env}' environment
27
+ NORESPONSE
28
+ elsif response['error']
29
+ puts <<-ERROR.gsub(/^\s+\|/, '')
30
+ |Error occurred: #{response['error']}
31
+ |Make sure that your Project ID and Project Key are correct:
32
+ |https://github.com/airbrake/airbrake-ruby#project_id--project_key
33
+ ERROR
34
+ else
35
+ puts <<-OUTPUT.gsub(/^\s+\|/, '')
36
+ |[ruby]
37
+ |description: #{RUBY_DESCRIPTION}
38
+ |
39
+ |#{if defined?(Rails)
40
+ "[rails]\nversion: #{Rails::VERSION::STRING}"
41
+ elsif defined?(Sinatra)
42
+ "[sinatra]\nversion: #{Sinatra::VERSION}"
43
+ end}
44
+ |
45
+ |[airbrake]
46
+ |version: #{Airbrake::AIRBRAKE_VERSION}
47
+ |
48
+ |[airbrake-ruby]
49
+ |version: #{Airbrake::Notice::NOTIFIER[:version]}
50
+ |
51
+ |[notifiers]
52
+ |#{notifiers}
53
+ |
54
+ |The output above contains useful information about your environment. Our support
55
+ |team may request this information if you have problems using the Airbrake gem;
56
+ |we would be really grateful if you could attach the output to your message.
57
+ |
58
+ |The test exception was sent. Find it here: #{response['url']}
59
+ OUTPUT
60
+ end
61
+ end
62
+
63
+ desc 'Notify Airbrake of a new deploy'
64
+ task :deploy do
65
+ if defined?(Rails)
66
+ initializer = Rails.root.join('config', 'initializers', 'airbrake.rb')
67
+
68
+ # Avoid loading the environment to speed up the deploy task and try guess
69
+ # the initializer file location.
70
+ if initializer.exist?
71
+ load initializer
72
+ else
73
+ Rake::Task[:environment].invoke
74
+ end
75
+ end
76
+
77
+ Airbrake.create_deploy(
78
+ environment: ENV['ENVIRONMENT'],
79
+ username: ENV['USERNAME'],
80
+ revision: ENV['REVISION'],
81
+ repository: ENV['REPOSITORY'],
82
+ version: ENV['VERSION']
83
+ )
84
+ end
85
+
86
+ desc 'Install a Heroku deploy hook to notify Airbrake of deploys'
87
+ task :install_heroku_deploy_hook do
88
+ app = ENV['HEROKU_APP']
89
+
90
+ config = Bundler.with_clean_env do
91
+ `heroku config --shell#{ " --app #{app}" if app }`
92
+ end
93
+
94
+ heroku_env = config.each_line.with_object({}) do |line, h|
95
+ h.merge!(Hash[*line.rstrip.split("\n").flat_map { |v| v.split('=', 2) }])
96
+ end
97
+
98
+ id = heroku_env['AIRBRAKE_PROJECT_ID']
99
+ key = heroku_env['AIRBRAKE_API_KEY']
100
+
101
+ exit!(1) if [id, key].any?(&:nil?)
102
+
103
+ unless (env = heroku_env['RAILS_ENV'])
104
+ env = 'production'
105
+ puts "Airbrake couldn't identify your app's environment, so the '#{env}'" \
106
+ " environment will be used."
107
+ end
108
+
109
+ url = "https://airbrake.io/api/v3/projects/#{id}/heroku-deploys?key=#{key}"
110
+ url << "&environment=#{env}"
111
+
112
+ command = %(heroku addons:create deployhooks:http --url="#{url}")
113
+ command << " --app #{app}" if app
114
+
115
+ puts "$ #{command}"
116
+ Bundler.with_clean_env { puts `#{command}` }
117
+ end
118
+ end
@@ -0,0 +1,19 @@
1
+ module Resque
2
+ module Failure
3
+ ##
4
+ # Provides Resque integration with Airbrake.
5
+ #
6
+ # @since v5.0.0
7
+ # @see https://github.com/resque/resque/wiki/Failure-Backends
8
+ class Airbrake < Base
9
+ def save
10
+ params = payload.merge(
11
+ component: 'resque',
12
+ action: payload['class'].to_s
13
+ )
14
+
15
+ ::Airbrake.notify_sync(exception, params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ module Airbrake
2
+ module Sidekiq
3
+ ##
4
+ # Provides integration with Sidekiq 2 and Sidekiq 3.
5
+ class ErrorHandler
6
+ # rubocop:disable Lint/RescueException
7
+ def call(_worker, context, _queue)
8
+ yield
9
+ rescue Exception => exception
10
+ notify_airbrake(exception, context)
11
+ raise exception
12
+ end
13
+ # rubocop:enable Lint/RescueException
14
+
15
+ private
16
+
17
+ def notify_airbrake(exception, context)
18
+ params = context.merge(component: 'sidekiq', action: context['class'])
19
+ Airbrake.notify(exception, params)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ if Sidekiq::VERSION < '3'
26
+ Sidekiq.configure_server do |config|
27
+ config.server_middleware do |chain|
28
+ chain.add(Airbrake::Sidekiq::ErrorHandler)
29
+ end
30
+ end
31
+ else
32
+ Sidekiq.configure_server do |config|
33
+ config.error_handlers << Airbrake::Sidekiq::ErrorHandler.new.method(:notify_airbrake)
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ ##
2
+ # We use Semantic Versioning v2.0.0
3
+ # More information: http://semver.org/
4
+ module Airbrake
5
+ AIRBRAKE_VERSION = '5.6.2'.freeze
6
+ end
@@ -0,0 +1,25 @@
1
+ ##
2
+ # Creates the Airbrake initializer file for Rails apps.
3
+ #
4
+ # @example Invokation from terminal
5
+ # rails generate airbrake PROJECT_KEY PROJECT_ID [NAME]
6
+ #
7
+ class AirbrakeGenerator < Rails::Generators::Base
8
+ # Adds current directory to source paths, so we can find the template file.
9
+ source_root File.expand_path('..', __FILE__)
10
+
11
+ argument :project_id, required: false
12
+ argument :project_key, required: false
13
+
14
+ ##
15
+ # Makes the NAME option optional, which allows to subclass from Base, so we
16
+ # can pass arguments to the ERB template.
17
+ #
18
+ # @see http://asciicasts.com/episodes/218-making-generators-in-rails-3
19
+ argument :name, type: :string, default: 'application'
20
+
21
+ desc 'Configures the Airbrake notifier with your project id and project key'
22
+ def generate_layout
23
+ template 'airbrake_initializer.rb.erb', 'config/initializers/airbrake.rb'
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ # Airbrake is an online tool that provides robust exception tracking in your Rails
2
+ # applications. In doing so, it allows you to easily review errors, tie an error
3
+ # to an individual piece of code, and trace the cause back to recent
4
+ # changes. Airbrake enables for easy categorization, searching, and prioritization
5
+ # of exceptions so that when errors occur, your team can quickly determine the
6
+ # root cause.
7
+ #
8
+ # Configuration details:
9
+ # https://github.com/airbrake/airbrake-ruby#configuration
10
+ Airbrake.configure do |c|
11
+ # You must set both project_id & project_key. To find your project_id and
12
+ # project_key navigate to your project's General Settings and copy the values
13
+ # from the right sidebar.
14
+ # https://github.com/airbrake/airbrake-ruby#project_id--project_key
15
+ <% if project_id -%>
16
+ c.project_id = <%= project_id %>
17
+ <% else -%>
18
+ c.project_id = ENV['AIRBRAKE_PROJECT_ID']
19
+ <% end -%>
20
+ <% if project_key -%>
21
+ c.project_key = '<%= project_key %>'
22
+ <% else -%>
23
+ c.project_key = ENV['AIRBRAKE_API_KEY']
24
+ <% end -%>
25
+
26
+ # Configures the root directory of your project. Expects a String or a
27
+ # Pathname, which represents the path to your project. Providing this option
28
+ # helps us to filter out repetitive data from backtrace frames and link to
29
+ # GitHub files from our dashboard.
30
+ # https://github.com/airbrake/airbrake-ruby#root_directory
31
+ c.root_directory = Rails.root
32
+
33
+ # By default, Airbrake Ruby outputs to STDOUT. In Rails apps it makes sense to
34
+ # use the Rails' logger.
35
+ # https://github.com/airbrake/airbrake-ruby#logger
36
+ c.logger = Rails.logger
37
+
38
+ # Configures the environment the application is running in. Helps the Airbrake
39
+ # dashboard to distinguish between exceptions occurring in different
40
+ # environments. By default, it's not set.
41
+ # NOTE: This option must be set in order to make the 'ignore_environments'
42
+ # option work.
43
+ # https://github.com/airbrake/airbrake-ruby#environment
44
+ c.environment = Rails.env
45
+
46
+ # Setting this option allows Airbrake to filter exceptions occurring in
47
+ # unwanted environments such as :test. By default, it is equal to an empty
48
+ # Array, which means Airbrake Ruby sends exceptions occurring in all
49
+ # environments.
50
+ # NOTE: This option *does not* work if you don't set the 'environment' option.
51
+ # https://github.com/airbrake/airbrake-ruby#ignore_environments
52
+ c.ignore_environments = %w(test)
53
+
54
+ # A list of parameters that should be filtered out of what is sent to
55
+ # Airbrake. By default, all "password" attributes will have their contents
56
+ # replaced.
57
+ # https://github.com/airbrake/airbrake-ruby#blacklist_keys
58
+ c.blacklist_keys = [/password/i]
59
+
60
+ # Alternatively, you can integrate with Rails' filter_parameters.
61
+ # Read more: https://goo.gl/gqQ1xS
62
+ # c.blacklist_keys = Rails.application.config.filter_parameters
63
+ end
64
+
65
+ # If Airbrake doesn't send any expected exceptions, we suggest to uncomment the
66
+ # line below. It might simplify debugging of background Airbrake workers, which
67
+ # can silently die.
68
+ # Thread.abort_on_exception = ['test', 'development'].include?(Rails.env)