airbrake 4.3.8 → 5.0.0
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.
- checksums.yaml +4 -4
- data/lib/airbrake/capistrano/tasks.rb +64 -0
- data/lib/airbrake/delayed_job/plugin.rb +48 -0
- data/lib/airbrake/rack/middleware.rb +45 -0
- data/lib/airbrake/rack/notice_builder.rb +80 -0
- data/lib/airbrake/rack/user.rb +51 -0
- data/lib/airbrake/rails/action_controller.rb +35 -0
- data/lib/airbrake/rails/active_job.rb +23 -0
- data/lib/airbrake/rails/active_record.rb +40 -0
- data/lib/airbrake/rails/railtie.rb +61 -0
- data/lib/airbrake/rake/task_ext.rb +61 -0
- data/lib/airbrake/rake/tasks.rb +93 -0
- data/lib/airbrake/resque/failure.rb +19 -0
- data/lib/airbrake/sidekiq/error_handler.rb +35 -0
- data/lib/airbrake/version.rb +4 -1
- data/lib/airbrake.rb +16 -185
- data/lib/generators/airbrake_generator.rb +25 -0
- data/lib/generators/airbrake_initializer.rb.erb +55 -0
- data/spec/airbrake_spec.rb +0 -0
- data/spec/apps/rack/dummy_app.rb +17 -0
- data/spec/apps/rails/dummy_app.rb +150 -0
- data/spec/apps/rails/dummy_task.rake +20 -0
- data/spec/apps/rails/logs/32.log +13358 -0
- data/spec/apps/rails/logs/40.log +6854 -0
- data/spec/apps/rails/logs/41.log +3170 -0
- data/spec/apps/rails/logs/42.log +23919 -0
- data/spec/apps/rails/logs/50.log +10976 -0
- data/spec/apps/sinatra/dummy_app.rb +12 -0
- data/spec/integration/rack/rack_spec.rb +17 -0
- data/spec/integration/rails/rails_spec.rb +135 -0
- data/spec/integration/rails/rake_spec.rb +160 -0
- data/spec/integration/shared_examples/rack_examples.rb +106 -0
- data/spec/integration/sinatra/sinatra_spec.rb +15 -0
- data/spec/spec_helper.rb +127 -0
- data/spec/unit/rack/middleware_spec.rb +80 -0
- data/spec/unit/rack/notice_builder_spec.rb +35 -0
- data/spec/unit/rack/user_spec.rb +78 -0
- data/spec/unit/rake/tasks_spec.rb +40 -0
- data/spec/unit/sidekiq/error_handler_spec.rb +29 -0
- metadata +108 -323
- data/CHANGELOG +0 -1716
- data/Gemfile +0 -3
- data/Guardfile +0 -6
- data/INSTALL +0 -20
- data/LICENSE +0 -61
- data/README.md +0 -148
- data/README_FOR_HEROKU_ADDON.md +0 -102
- data/Rakefile +0 -179
- data/TESTED_AGAINST +0 -7
- data/airbrake.gemspec +0 -41
- data/bin/airbrake +0 -12
- data/features/metal.feature +0 -34
- data/features/rack.feature +0 -60
- data/features/rails.feature +0 -324
- data/features/rake.feature +0 -33
- data/features/sinatra.feature +0 -126
- data/features/step_definitions/file_steps.rb +0 -14
- data/features/step_definitions/rack_steps.rb +0 -27
- data/features/step_definitions/rails_application_steps.rb +0 -267
- data/features/step_definitions/rake_steps.rb +0 -22
- data/features/support/airbrake_shim.rb.template +0 -11
- data/features/support/aruba.rb +0 -5
- data/features/support/env.rb +0 -39
- data/features/support/matchers.rb +0 -35
- data/features/support/rails.rb +0 -156
- data/features/support/rake/Rakefile +0 -77
- data/features/user_informer.feature +0 -57
- data/generators/airbrake/airbrake_generator.rb +0 -94
- data/generators/airbrake/lib/insert_commands.rb +0 -34
- data/generators/airbrake/lib/rake_commands.rb +0 -24
- data/generators/airbrake/templates/airbrake_tasks.rake +0 -25
- data/generators/airbrake/templates/capistrano_hook.rb +0 -6
- data/generators/airbrake/templates/initializer.rb +0 -4
- data/install.rb +0 -1
- data/lib/airbrake/backtrace.rb +0 -103
- data/lib/airbrake/capistrano.rb +0 -103
- data/lib/airbrake/capistrano3.rb +0 -3
- data/lib/airbrake/cli/client.rb +0 -76
- data/lib/airbrake/cli/options.rb +0 -45
- data/lib/airbrake/cli/printer.rb +0 -33
- data/lib/airbrake/cli/project.rb +0 -17
- data/lib/airbrake/cli/project_factory.rb +0 -33
- data/lib/airbrake/cli/runner.rb +0 -49
- data/lib/airbrake/cli/validator.rb +0 -8
- data/lib/airbrake/configuration.rb +0 -366
- data/lib/airbrake/jobs/send_job.rb +0 -7
- data/lib/airbrake/notice.rb +0 -411
- data/lib/airbrake/rack.rb +0 -64
- data/lib/airbrake/rails/action_controller_catcher.rb +0 -32
- data/lib/airbrake/rails/controller_methods.rb +0 -146
- data/lib/airbrake/rails/error_lookup.rb +0 -35
- data/lib/airbrake/rails/middleware.rb +0 -63
- data/lib/airbrake/rails.rb +0 -45
- data/lib/airbrake/rails3_tasks.rb +0 -126
- data/lib/airbrake/railtie.rb +0 -46
- data/lib/airbrake/rake_handler.rb +0 -75
- data/lib/airbrake/response.rb +0 -29
- data/lib/airbrake/sender.rb +0 -213
- data/lib/airbrake/shared_tasks.rb +0 -59
- data/lib/airbrake/sidekiq.rb +0 -8
- data/lib/airbrake/sinatra.rb +0 -40
- data/lib/airbrake/tasks/airbrake.cap +0 -28
- data/lib/airbrake/tasks.rb +0 -81
- data/lib/airbrake/user_informer.rb +0 -36
- data/lib/airbrake/utils/params_cleaner.rb +0 -141
- data/lib/airbrake/utils/rack_filters.rb +0 -45
- data/lib/airbrake_tasks.rb +0 -62
- data/lib/rails/generators/airbrake/airbrake_generator.rb +0 -155
- data/lib/templates/rescue.erb +0 -91
- data/rails/init.rb +0 -1
- data/resources/README.md +0 -34
- data/resources/airbrake_2_4.xsd +0 -89
- data/resources/airbrake_3_0.json +0 -52
- data/resources/ca-bundle.crt +0 -3376
- data/script/integration_test.rb +0 -35
- data/test/airbrake_tasks_test.rb +0 -161
- data/test/backtrace_test.rb +0 -215
- data/test/capistrano_test.rb +0 -44
- data/test/configuration_test.rb +0 -303
- data/test/controller_methods_test.rb +0 -230
- data/test/helper.rb +0 -233
- data/test/integration/catcher_test.rb +0 -371
- data/test/integration.rb +0 -13
- data/test/logger_test.rb +0 -79
- data/test/notice_test.rb +0 -494
- data/test/notifier_test.rb +0 -288
- data/test/params_cleaner_test.rb +0 -204
- data/test/rack_test.rb +0 -62
- data/test/rails_initializer_test.rb +0 -36
- data/test/recursion_test.rb +0 -10
- data/test/response_test.rb +0 -18
- data/test/sender_test.rb +0 -335
- data/test/support/response_shim.xml +0 -4
- data/test/user_informer_test.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 444112058d438d1d60afddd2d18fe604e0056c43
|
4
|
+
data.tar.gz: 275985dd0bb4949f08e7d881ac74a2ce039f1351
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aff3b34806a8391c5cb917cc8cd02e3de21120cec7f04d214f5b85becbb38495b4de039e952e2f76f03990da68640fcc89549151e26bb57560039493af0eb775
|
7
|
+
data.tar.gz: 6438d408657247dbb1d6cf93cf9c77ab9d2f9e389ec64af55d6d5dd54b8311e910ca2d91d97739d86a3b9a0492421abce818919d9fe61d377b7c20f2af5078c7
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
if defined?(Capistrano::VERSION) &&
|
5
|
+
Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
|
6
|
+
namespace :airbrake do
|
7
|
+
desc "Notify Airbrake of the deploy"
|
8
|
+
task :deploy do
|
9
|
+
on roles(:all) do
|
10
|
+
within release_path do
|
11
|
+
with rails_env: fetch(:rails_env, fetch(:stage)) do
|
12
|
+
execute :rake, <<-CMD
|
13
|
+
airbrake:deploy USERNAME=#{Shellwords.shellescape(local_user)} \
|
14
|
+
ENVIRONMENT=#{fetch(:rails_env, fetch(:stage))} \
|
15
|
+
REVISION=#{fetch(:current_revision)} \
|
16
|
+
REPOSITORY=#{fetch(:repo_url)} \
|
17
|
+
VERSION=#{fetch(:app_version)}
|
18
|
+
CMD
|
19
|
+
|
20
|
+
info 'Notified Airbrake of the deploy'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
module Airbrake
|
28
|
+
##
|
29
|
+
# The Capistrano v2 integration.
|
30
|
+
module Capistrano
|
31
|
+
# rubocop:disable Metrics/AbcSize
|
32
|
+
def self.load_into(config)
|
33
|
+
config.load do
|
34
|
+
after 'deploy', 'airbrake:deploy'
|
35
|
+
after 'deploy:migrations', 'airbrake:deploy'
|
36
|
+
after 'deploy:cold', 'airbrake:deploy'
|
37
|
+
|
38
|
+
namespace :airbrake do
|
39
|
+
desc "Notify Airbrake of the deploy"
|
40
|
+
task :deploy, except: { no_release: true }, on_error: :continue do
|
41
|
+
FileUtils.cd(config.release_path) do
|
42
|
+
username = Shellwords.shellescape(ENV['USER'] || ENV['USERNAME'])
|
43
|
+
|
44
|
+
system(<<-CMD)
|
45
|
+
bundle exec rake airbrake:deploy \
|
46
|
+
USERNAME=#{username} \
|
47
|
+
ENVIRONMENT=#{fetch(:rails_env, 'production')} \
|
48
|
+
REVISION=#{current_revision.strip} \
|
49
|
+
REPOSITORY=#{repository} \
|
50
|
+
VERSION=#{fetch(:app_version, nil)}
|
51
|
+
CMD
|
52
|
+
end
|
53
|
+
|
54
|
+
logger.info 'Notified Airbrake of the deploy'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
# rubocop:enable Metrics/AbcSize
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Airbrake::Capistrano.load_into(Capistrano::Configuration.instance)
|
64
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Plugins
|
3
|
+
##
|
4
|
+
# Provides integration with Delayed Job.
|
5
|
+
# rubocop:disable Lint/RescueException
|
6
|
+
class Airbrake < ::Delayed::Plugin
|
7
|
+
callbacks do |lifecycle|
|
8
|
+
lifecycle.around(:invoke_job) do |job, *args, &block|
|
9
|
+
begin
|
10
|
+
# Forward the call to the next callback in the callback chain
|
11
|
+
block.call(job, *args)
|
12
|
+
rescue Exception => exception
|
13
|
+
params = job.as_json.merge(
|
14
|
+
component: 'delayed_job',
|
15
|
+
action: job.payload_object.class.name
|
16
|
+
)
|
17
|
+
|
18
|
+
# If DelayedJob is used through ActiveJob, it contains extra info.
|
19
|
+
if job.payload_object.respond_to?(:job_data)
|
20
|
+
params[:active_job] = job.payload_object.job_data
|
21
|
+
end
|
22
|
+
|
23
|
+
::Airbrake.notify(exception, params)
|
24
|
+
raise exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# rubocop:enable Lint/RescueException
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if RUBY_ENGINE == 'jruby' && defined?(Delayed::Backend::ActiveRecord::Job)
|
34
|
+
##
|
35
|
+
# Workaround against JRuby bug:
|
36
|
+
# https://github.com/jruby/jruby/issues/3338
|
37
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
38
|
+
class Delayed::Backend::ActiveRecord::Job
|
39
|
+
alias_method :old_to_ary, :to_ary
|
40
|
+
|
41
|
+
def to_ary
|
42
|
+
old_to_ary || [self]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
46
|
+
end
|
47
|
+
|
48
|
+
Delayed::Worker.plugins << Delayed::Plugins::Airbrake
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
##
|
4
|
+
# Airbrake Rack middleware for Rails and Sinatra applications (or any other
|
5
|
+
# Rack-compliant app). Any errors raised by the upstream application will be
|
6
|
+
# delivered to Airbrake and re-raised.
|
7
|
+
#
|
8
|
+
# The middleware automatically sends information about the framework that
|
9
|
+
# uses it (name and version).
|
10
|
+
class Middleware
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Rescues any exceptions, sends them to Airbrake and re-raises the
|
17
|
+
# exception.
|
18
|
+
# @param [Hash] env the Rack environment
|
19
|
+
def call(env)
|
20
|
+
# rubocop:disable Lint/RescueException
|
21
|
+
begin
|
22
|
+
response = @app.call(env)
|
23
|
+
rescue Exception => ex
|
24
|
+
notify_airbrake(ex, env)
|
25
|
+
raise ex
|
26
|
+
end
|
27
|
+
# rubocop:enable Lint/RescueException
|
28
|
+
|
29
|
+
# The internal framework middlewares store exceptions inside the Rack
|
30
|
+
# env. See: https://goo.gl/Kd694n
|
31
|
+
exception = env['action_dispatch.exception'] || env['sinatra.error']
|
32
|
+
notify_airbrake(exception, env) if exception
|
33
|
+
|
34
|
+
response
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def notify_airbrake(exception, env)
|
40
|
+
notice = NoticeBuilder.new(env).build_notice(exception)
|
41
|
+
Airbrake.notify(notice)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
##
|
4
|
+
# A helper class for filling notices with all sorts of useful information
|
5
|
+
# coming from the Rack environment.
|
6
|
+
class NoticeBuilder
|
7
|
+
##
|
8
|
+
# @return [String] the name of the host machine
|
9
|
+
HOSTNAME = Socket.gethostname.freeze
|
10
|
+
|
11
|
+
##
|
12
|
+
# @param [Hash{String=>Object}] rack_env The Rack environment
|
13
|
+
def initialize(rack_env)
|
14
|
+
@rack_env = rack_env
|
15
|
+
@request = ::Rack::Request.new(rack_env)
|
16
|
+
@controller = rack_env['action_controller.instance']
|
17
|
+
@session = @request.session
|
18
|
+
@user = Airbrake::Rack::User.extract(rack_env)
|
19
|
+
|
20
|
+
@framework_version =
|
21
|
+
if defined?(::Rails)
|
22
|
+
"Rails/#{::Rails.version}"
|
23
|
+
elsif defined?(::Sinatra)
|
24
|
+
"Sinatra/#{Sinatra::VERSION}"
|
25
|
+
else
|
26
|
+
"Rack.version/#{::Rack.version} Rack.release/#{::Rack.release}"
|
27
|
+
end.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Adds context, session, params and other fields based on the Rack env.
|
32
|
+
#
|
33
|
+
# @param [Exception] exception
|
34
|
+
# @return [Airbrake::Notice] the notice with extra information
|
35
|
+
def build_notice(exception)
|
36
|
+
notice = Airbrake.build_notice(exception)
|
37
|
+
|
38
|
+
add_context(notice)
|
39
|
+
add_session(notice)
|
40
|
+
add_params(notice)
|
41
|
+
|
42
|
+
notice
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add_context(notice)
|
48
|
+
context = notice[:context]
|
49
|
+
|
50
|
+
context[:url] = @request.url
|
51
|
+
context[:userAgent] = @request.user_agent
|
52
|
+
context[:hostname] = HOSTNAME
|
53
|
+
|
54
|
+
if context.key?(:version)
|
55
|
+
context[:version] += " #{@framework_version}"
|
56
|
+
else
|
57
|
+
context[:version] = @framework_version
|
58
|
+
end
|
59
|
+
|
60
|
+
if @controller
|
61
|
+
context[:component] = @controller.controller_name
|
62
|
+
context[:action] = @controller.action_name
|
63
|
+
end
|
64
|
+
|
65
|
+
notice[:context].merge!(@user.to_hash) if @user
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_session(notice)
|
71
|
+
notice[:session] = @session if @session
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_params(notice)
|
75
|
+
params = @request.env['action_dispatch.request.parameters']
|
76
|
+
notice[:params] = params if params
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
##
|
4
|
+
# Represents an authenticated Warden user, which can be converted to
|
5
|
+
# Airbrake's payload format.
|
6
|
+
class User
|
7
|
+
# Finds the Warden user in the Rack environment and creates a new user
|
8
|
+
# wrapper.
|
9
|
+
#
|
10
|
+
# @param [Hash{String=>Object}] rack_env The Rack environment
|
11
|
+
# @return [Airbrake::Rack::User, nil]
|
12
|
+
def self.extract(rack_env)
|
13
|
+
return unless (warden = rack_env['warden'])
|
14
|
+
new(warden.user(run_callbacks: false))
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# @param [Warden::Proxy] warden_user
|
19
|
+
def initialize(warden_user)
|
20
|
+
@warden_user = warden_user
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Converts the user to Airbrake payload user.
|
25
|
+
# @return [Hash{Symbol=>String}] the hash with retrieved user details
|
26
|
+
def to_hash
|
27
|
+
user = {}
|
28
|
+
|
29
|
+
user[:id] = try_to_get(:id)
|
30
|
+
user[:name] = full_name
|
31
|
+
user[:username] = try_to_get(:username)
|
32
|
+
user[:email] = try_to_get(:email)
|
33
|
+
|
34
|
+
user = user.delete_if { |_key, val| val.nil? }
|
35
|
+
user.empty? ? user : { user: user }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def try_to_get(key)
|
41
|
+
String(@warden_user.__send__(key)) if @warden_user.respond_to?(key)
|
42
|
+
end
|
43
|
+
|
44
|
+
def full_name
|
45
|
+
# Try to get first and last names. If that fails, try to get just 'name'.
|
46
|
+
name = [try_to_get(:first_name), try_to_get(:last_name)].compact.join(' ')
|
47
|
+
name.empty? ? try_to_get(:name) : name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rails
|
3
|
+
##
|
4
|
+
# Contains helper methods that can be used inside Rails controllers to send
|
5
|
+
# notices to Airbrake. The main benefit of using them instead of the direct
|
6
|
+
# API is that they automatically add information from the Rack environment
|
7
|
+
# to notices.
|
8
|
+
module ActionController
|
9
|
+
private
|
10
|
+
|
11
|
+
##
|
12
|
+
# A helper method for sending notices to Airbrake *asynchronously*.
|
13
|
+
# Attaches information from the Rack env.
|
14
|
+
# @see Airbrake#notify, #notify_airbrake_sync
|
15
|
+
def notify_airbrake(exception, parameters = {}, notifier = :default)
|
16
|
+
Airbrake.notify(build_notice(exception), parameters, notifier)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# A helper method for sending notices to Airbrake *synchronously*.
|
21
|
+
# Attaches information from the Rack env.
|
22
|
+
# @see Airbrake#notify_sync, #notify_airbrake
|
23
|
+
def notify_airbrake_sync(exception, parameters = {}, notifier = :default)
|
24
|
+
Airbrake.notify_sync(build_notice(exception), parameters, notifier)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# @param [Exception] exception
|
29
|
+
# @return [Airbrake::Notice] the notice with information from the Rack env
|
30
|
+
def build_notice(exception)
|
31
|
+
Airbrake::Rack::NoticeBuilder.new(request.env).build_notice(exception)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
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
|
+
rescue_from(Exception) do |exception|
|
10
|
+
notice = Airbrake.build_notice(exception)
|
11
|
+
|
12
|
+
notice[:context][:component] = self.class.name
|
13
|
+
notice[:context][:action] = job_id
|
14
|
+
|
15
|
+
notice[:params] = as_json
|
16
|
+
|
17
|
+
Airbrake.notify(notice)
|
18
|
+
raise exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
+
# @return [Array<Symbol>] the hooks that needs fixing
|
17
|
+
KINDS = [:commit, :rollback].freeze
|
18
|
+
|
19
|
+
##
|
20
|
+
# Patches default +run_callbacks+ with our version, which is capable of
|
21
|
+
# notifying about exceptions.
|
22
|
+
#
|
23
|
+
# rubocop:disable Lint/RescueException
|
24
|
+
def run_callbacks(kind, *args, &block)
|
25
|
+
# Let the post process handle the exception if it's not a bugged hook.
|
26
|
+
return super unless KINDS.include?(kind)
|
27
|
+
|
28
|
+
# Handle the exception ourselves. The 'ex' exception won't be
|
29
|
+
# propagated, therefore we must notify it here.
|
30
|
+
begin
|
31
|
+
super
|
32
|
+
rescue Exception => ex
|
33
|
+
Airbrake.notify(ex)
|
34
|
+
raise ex
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# rubocop:enable Lint/RescueException
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
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 =~ /\A5\./
|
15
|
+
# Avoid the warning about deprecated strings.
|
16
|
+
app.config.middleware.insert_after(
|
17
|
+
ActionDispatch::DebugExceptions, Airbrake::Rack::Middleware
|
18
|
+
)
|
19
|
+
else
|
20
|
+
app.config.middleware.insert_after(
|
21
|
+
ActionDispatch::DebugExceptions, 'Airbrake::Rack::Middleware'
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
rake_tasks do
|
27
|
+
# Report exceptions occurring in Rake tasks.
|
28
|
+
require 'airbrake/rake/task_ext'
|
29
|
+
|
30
|
+
# Defines tasks such as `airbrake:test` & `airbrake:deploy`.
|
31
|
+
require 'airbrake/rake/tasks'
|
32
|
+
end
|
33
|
+
|
34
|
+
initializer('airbrake.action_controller') do
|
35
|
+
ActiveSupport.on_load(:action_controller) do
|
36
|
+
# Patches ActionController with methods that allow us to retrieve
|
37
|
+
# interesting request data. Appends that information to notices.
|
38
|
+
require 'airbrake/rails/action_controller'
|
39
|
+
include Airbrake::Rails::ActionController
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
initializer('airbrake.active_record') do
|
44
|
+
ActiveSupport.on_load(:active_record) do
|
45
|
+
# Reports exceptions occurring in some bugged ActiveRecord callbacks.
|
46
|
+
# Applicable only to the versions of Rails lower than 4.2.
|
47
|
+
require 'airbrake/rails/active_record'
|
48
|
+
include Airbrake::Rails::ActiveRecord
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
initializer('airbrake.active_job') do
|
53
|
+
ActiveSupport.on_load(:active_job) do
|
54
|
+
# Reports exceptions occurring in ActiveJob jobs.
|
55
|
+
require 'airbrake/rails/active_job'
|
56
|
+
include Airbrake::Rails::ActiveJob
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,61 @@
|
|
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_method :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
|
+
notice = Airbrake.build_notice(ex)
|
22
|
+
notice[:context][:component] = 'rake'
|
23
|
+
notice[:context][:action] = name
|
24
|
+
notice[:params] = {
|
25
|
+
rake_task: task_info,
|
26
|
+
execute_args: args,
|
27
|
+
argv: ARGV.join(' ')
|
28
|
+
}
|
29
|
+
|
30
|
+
Airbrake.notify(notice)
|
31
|
+
raise ex
|
32
|
+
end
|
33
|
+
# rubocop:enable Lint/RescueException
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
38
|
+
def task_info
|
39
|
+
info = {}
|
40
|
+
|
41
|
+
info[:name] = name
|
42
|
+
info[:timestamp] = timestamp.to_s
|
43
|
+
info[:investigation] = investigation
|
44
|
+
|
45
|
+
info[:full_comment] = full_comment if full_comment
|
46
|
+
info[:arg_names] = arg_names if arg_names.any?
|
47
|
+
info[:arg_description] = arg_description if arg_description
|
48
|
+
info[:locations] = locations if locations.any?
|
49
|
+
info[:sources] = sources if sources.any?
|
50
|
+
|
51
|
+
if prerequisite_tasks.any?
|
52
|
+
info[:prerequisite_tasks] = prerequisite_tasks.map do |p|
|
53
|
+
p.__send__(:task_info)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
info
|
58
|
+
end
|
59
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,93 @@
|
|
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
|
+
puts <<OUTPUT
|
19
|
+
[ruby]
|
20
|
+
description: #{RUBY_DESCRIPTION}
|
21
|
+
|
22
|
+
#{if defined?(Rails)
|
23
|
+
"[rails]\nversion: #{Rails::VERSION::STRING}"
|
24
|
+
elsif defined?(Sinatra)
|
25
|
+
"[sinatra]\nversion: #{Sinatra::VERSION}"
|
26
|
+
end}
|
27
|
+
|
28
|
+
[airbrake]
|
29
|
+
version: #{Airbrake::AIRBRAKE_VERSION}
|
30
|
+
|
31
|
+
[airbrake-ruby]
|
32
|
+
version: #{Airbrake::Notice::NOTIFIER[:version]}
|
33
|
+
|
34
|
+
[notifiers]
|
35
|
+
#{notifiers}
|
36
|
+
|
37
|
+
The output above contains useful information about your environment. Our support
|
38
|
+
team may request this information if you have problems using the Airbrake gem;
|
39
|
+
we would be really grateful if you could attach the output to your message.
|
40
|
+
|
41
|
+
The test exception was sent. Find it here: #{response['url']}
|
42
|
+
OUTPUT
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Notify Airbrake of a new deploy'
|
46
|
+
task :deploy do
|
47
|
+
if defined?(Rails)
|
48
|
+
initializer = Rails.root.join('config', 'initializers', 'airbrake.rb')
|
49
|
+
|
50
|
+
# Avoid loading the environment to speed up the deploy task and try guess
|
51
|
+
# the initializer file location.
|
52
|
+
if initializer.exist?
|
53
|
+
load initializer
|
54
|
+
else
|
55
|
+
Rake::Task[:environment].invoke
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Airbrake.create_deploy(
|
60
|
+
environment: ENV['ENVIRONMENT'],
|
61
|
+
username: ENV['USERNAME'],
|
62
|
+
revision: ENV['REVISION'],
|
63
|
+
repository: ENV['REPOSITORY'],
|
64
|
+
version: ENV['VERSION']
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
desc 'Install a Heroku deploy hook to notify Airbrake of deploys'
|
69
|
+
task :install_heroku_deploy_hook do
|
70
|
+
app = ENV['HEROKU_APP']
|
71
|
+
|
72
|
+
config = Bundler.with_clean_env do
|
73
|
+
`heroku config --shell#{ " --app #{app}" if app }`
|
74
|
+
end
|
75
|
+
|
76
|
+
heroku_env = config.each_line.with_object({}) do |line, h|
|
77
|
+
h.merge!(Hash[*line.rstrip.split('=')])
|
78
|
+
end
|
79
|
+
|
80
|
+
id = heroku_env['AIRBRAKE_PROJECT_ID']
|
81
|
+
key = heroku_env['AIRBRAKE_API_KEY']
|
82
|
+
|
83
|
+
exit!(1) if [id, key].any?(&:nil?)
|
84
|
+
|
85
|
+
url = "https://airbrake.io/api/v3/projects/#{id}/heroku-deploys?key=#{key}"
|
86
|
+
|
87
|
+
command = %(heroku addons:create deployhooks:http --url="#{url}")
|
88
|
+
command << " --app #{app}" if app
|
89
|
+
|
90
|
+
puts "$ #{command}"
|
91
|
+
Bundler.with_clean_env { puts `#{command}` }
|
92
|
+
end
|
93
|
+
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
|