airbrake 9.5.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 +7 -0
- data/lib/airbrake.rb +30 -0
- data/lib/airbrake/capistrano.rb +6 -0
- data/lib/airbrake/capistrano/capistrano2.rb +38 -0
- data/lib/airbrake/capistrano/capistrano3.rb +21 -0
- data/lib/airbrake/delayed_job.rb +48 -0
- data/lib/airbrake/logger.rb +101 -0
- data/lib/airbrake/rack.rb +35 -0
- data/lib/airbrake/rack/context_filter.rb +58 -0
- data/lib/airbrake/rack/http_headers_filter.rb +42 -0
- data/lib/airbrake/rack/http_params_filter.rb +25 -0
- data/lib/airbrake/rack/instrumentable.rb +28 -0
- data/lib/airbrake/rack/middleware.rb +100 -0
- data/lib/airbrake/rack/request_body_filter.rb +31 -0
- data/lib/airbrake/rack/request_store.rb +32 -0
- data/lib/airbrake/rack/route_filter.rb +53 -0
- data/lib/airbrake/rack/session_filter.rb +23 -0
- data/lib/airbrake/rack/user.rb +70 -0
- data/lib/airbrake/rack/user_filter.rb +23 -0
- data/lib/airbrake/rails.rb +32 -0
- data/lib/airbrake/rails/action_cable.rb +33 -0
- data/lib/airbrake/rails/action_cable/notify_callback.rb +20 -0
- data/lib/airbrake/rails/action_controller.rb +35 -0
- data/lib/airbrake/rails/action_controller_notify_subscriber.rb +28 -0
- data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +46 -0
- data/lib/airbrake/rails/action_controller_route_subscriber.rb +46 -0
- data/lib/airbrake/rails/active_job.rb +33 -0
- data/lib/airbrake/rails/active_record.rb +34 -0
- data/lib/airbrake/rails/active_record_subscriber.rb +42 -0
- data/lib/airbrake/rails/app.rb +43 -0
- data/lib/airbrake/rails/backtrace_cleaner.rb +10 -0
- data/lib/airbrake/rails/curb.rb +35 -0
- data/lib/airbrake/rails/event.rb +83 -0
- data/lib/airbrake/rails/excon_subscriber.rb +21 -0
- data/lib/airbrake/rails/http.rb +12 -0
- data/lib/airbrake/rails/http_client.rb +10 -0
- data/lib/airbrake/rails/net_http.rb +10 -0
- data/lib/airbrake/rails/railtie.rb +141 -0
- data/lib/airbrake/rails/typhoeus.rb +12 -0
- data/lib/airbrake/rake.rb +63 -0
- data/lib/airbrake/rake/tasks.rb +110 -0
- data/lib/airbrake/resque.rb +29 -0
- data/lib/airbrake/shoryuken.rb +40 -0
- data/lib/airbrake/sidekiq.rb +47 -0
- data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +51 -0
- data/lib/airbrake/sneakers.rb +34 -0
- data/lib/airbrake/version.rb +5 -0
- data/lib/generators/airbrake_generator.rb +23 -0
- data/lib/generators/airbrake_initializer.rb.erb +78 -0
- metadata +416 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 29bdd7916d90d84ac4933c2ce14d9069bd719a371bf822a3b886175841b2005c
|
4
|
+
data.tar.gz: 94f382b83ce554984a9c4e8162241be85baa78739d928e3c74081cfb17217f1a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7e27d67804da299808bd87f6d2f201ab778ef344ff377283536d5be2082c579df9e54102eb83d48a5cadc78cf434bfcb7bf3c999a816b449f8930e539c96743
|
7
|
+
data.tar.gz: '028d1865c3e42686c54455164087d401f3dabbd1380b915aec7ca8191e0f777dc26c32930c9118bd160ef1bd6ba63f1fac289a4786f9fc720c98f7a3eadfe2ae'
|
data/lib/airbrake.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'English'
|
3
|
+
|
4
|
+
# Core library that sends notices.
|
5
|
+
# See: https://github.com/airbrake/airbrake-ruby
|
6
|
+
require 'airbrake-ruby'
|
7
|
+
|
8
|
+
require 'airbrake/version'
|
9
|
+
|
10
|
+
# Automatically load needed files for the environment the library is running in.
|
11
|
+
if defined?(Rack)
|
12
|
+
require 'airbrake/rack'
|
13
|
+
|
14
|
+
require 'airbrake/rails' if defined?(Rails)
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'airbrake/rake' if defined?(Rake::Task)
|
18
|
+
require 'airbrake/resque' if defined?(Resque)
|
19
|
+
require 'airbrake/sidekiq' if defined?(Sidekiq)
|
20
|
+
require 'airbrake/shoryuken' if defined?(Shoryuken)
|
21
|
+
require 'airbrake/delayed_job' if defined?(Delayed)
|
22
|
+
require 'airbrake/sneakers' if defined?(Sneakers)
|
23
|
+
|
24
|
+
require 'airbrake/logger'
|
25
|
+
|
26
|
+
# Notify of unhandled exceptions, if there were any, but ignore SystemExit.
|
27
|
+
at_exit do
|
28
|
+
Airbrake.notify_sync($ERROR_INFO) if $ERROR_INFO
|
29
|
+
Airbrake.close
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Airbrake
|
2
|
+
# The Capistrano v2 integration.
|
3
|
+
module Capistrano
|
4
|
+
# rubocop:disable Metrics/AbcSize
|
5
|
+
def self.load_into(config)
|
6
|
+
config.load do
|
7
|
+
after 'deploy', 'airbrake:deploy'
|
8
|
+
after 'deploy:migrations', 'airbrake:deploy'
|
9
|
+
after 'deploy:cold', 'airbrake:deploy'
|
10
|
+
|
11
|
+
namespace :airbrake do
|
12
|
+
desc "Notify Airbrake of the deploy"
|
13
|
+
task :deploy, except: { no_release: true }, on_error: :continue do
|
14
|
+
run(
|
15
|
+
<<-CMD, once: true
|
16
|
+
cd #{config.release_path} && \
|
17
|
+
|
18
|
+
RACK_ENV=#{fetch(:rack_env, nil)} \
|
19
|
+
RAILS_ENV=#{fetch(:rails_env, nil)} \
|
20
|
+
|
21
|
+
bundle exec rake airbrake:deploy \
|
22
|
+
USERNAME=#{Shellwords.shellescape(ENV['USER'] || ENV['USERNAME'])} \
|
23
|
+
ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, 'production'))} \
|
24
|
+
REVISION=#{current_revision.strip} \
|
25
|
+
REPOSITORY=#{repository} \
|
26
|
+
VERSION=#{fetch(:app_version, nil)}
|
27
|
+
CMD
|
28
|
+
)
|
29
|
+
logger.info 'Notified Airbrake of the deploy'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# rubocop:enable Metrics/AbcSize
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Airbrake::Capistrano.load_into(Capistrano::Configuration.instance)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :airbrake do
|
2
|
+
desc "Notify Airbrake of the deploy"
|
3
|
+
task :deploy do
|
4
|
+
role = roles(:all, select: :primary).first || roles(:all).first
|
5
|
+
on role do
|
6
|
+
within release_path do
|
7
|
+
with rails_env: fetch(:rails_env, fetch(:stage)) do
|
8
|
+
execute :bundle, :exec, :rake, <<-CMD
|
9
|
+
airbrake:deploy USERNAME=#{Shellwords.shellescape(local_user)} \
|
10
|
+
ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, fetch(:stage)))} \
|
11
|
+
REVISION=#{fetch(:current_revision)} \
|
12
|
+
REPOSITORY=#{fetch(:repo_url)} \
|
13
|
+
VERSION=#{fetch(:app_version)}
|
14
|
+
CMD
|
15
|
+
|
16
|
+
info 'Notified Airbrake of the deploy'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Plugins
|
3
|
+
# Provides integration with Delayed Job.
|
4
|
+
# rubocop:disable Lint/RescueException
|
5
|
+
class Airbrake < ::Delayed::Plugin
|
6
|
+
callbacks do |lifecycle|
|
7
|
+
lifecycle.around(:invoke_job) do |job, *args, &block|
|
8
|
+
begin
|
9
|
+
# Forward the call to the next callback in the callback chain
|
10
|
+
block.call(job, *args)
|
11
|
+
rescue Exception => exception
|
12
|
+
params = job.as_json
|
13
|
+
|
14
|
+
# If DelayedJob is used through ActiveJob, it contains extra info.
|
15
|
+
if job.payload_object.respond_to?(:job_data)
|
16
|
+
params[:active_job] = job.payload_object.job_data
|
17
|
+
job_class = job.payload_object.job_data['job_class']
|
18
|
+
end
|
19
|
+
|
20
|
+
::Airbrake.notify(exception, params) do |notice|
|
21
|
+
notice[:context][:component] = 'delayed_job'
|
22
|
+
notice[:context][:action] = job_class || job.payload_object.class.name
|
23
|
+
end
|
24
|
+
|
25
|
+
raise exception
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# rubocop:enable Lint/RescueException
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if RUBY_ENGINE == 'jruby' && defined?(Delayed::Backend::ActiveRecord::Job)
|
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 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,101 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
module Airbrake
|
5
|
+
# Decorator for +Logger+ from stdlib. Endows loggers the ability to both log
|
6
|
+
# and report errors to Airbrake.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # Create a logger like you normally do and decorate it.
|
10
|
+
# logger = Airbrake::AirbrakeLogger.new(Logger.new(STDOUT))
|
11
|
+
#
|
12
|
+
# # Just use the logger like you normally do.
|
13
|
+
# logger.fatal('oops')
|
14
|
+
class AirbrakeLogger < SimpleDelegator
|
15
|
+
# @example
|
16
|
+
# # Assign a custom Airbrake notifier
|
17
|
+
# logger.airbrake_notifier = Airbrake::NoticeNotifier.new
|
18
|
+
# @return [Airbrake::Notifier] notifier to be used to send notices
|
19
|
+
attr_accessor :airbrake_notifier
|
20
|
+
|
21
|
+
# @return [Integer]
|
22
|
+
attr_reader :airbrake_level
|
23
|
+
|
24
|
+
def initialize(logger)
|
25
|
+
__setobj__(logger)
|
26
|
+
@airbrake_notifier = Airbrake
|
27
|
+
self.level = logger.level
|
28
|
+
end
|
29
|
+
|
30
|
+
# @see Logger#warn
|
31
|
+
def warn(progname = nil, &block)
|
32
|
+
notify_airbrake(Logger::WARN, progname)
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Logger#error
|
37
|
+
def error(progname = nil, &block)
|
38
|
+
notify_airbrake(Logger::ERROR, progname)
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
# @see Logger#fatal
|
43
|
+
def fatal(progname = nil, &block)
|
44
|
+
notify_airbrake(Logger::FATAL, progname)
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
# @see Logger#unknown
|
49
|
+
def unknown(progname = nil, &block)
|
50
|
+
notify_airbrake(Logger::UNKNOWN, progname)
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
# @see Logger#level=
|
55
|
+
def level=(value)
|
56
|
+
self.airbrake_level = value < Logger::WARN ? Logger::WARN : value
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
# Sets airbrake severity level. Does not permit values below `Logger::WARN`.
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
# logger.airbrake_level = Logger::FATAL
|
64
|
+
# @return [void]
|
65
|
+
def airbrake_level=(level)
|
66
|
+
if level < Logger::WARN
|
67
|
+
raise "Airbrake severity level #{level} is not allowed. " \
|
68
|
+
"Minimum allowed level is #{Logger::WARN}"
|
69
|
+
end
|
70
|
+
@airbrake_level = level
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def notify_airbrake(severity, progname)
|
76
|
+
return if severity < @airbrake_level || !@airbrake_notifier
|
77
|
+
|
78
|
+
@airbrake_notifier.notify(progname) do |notice|
|
79
|
+
# Get rid of unwanted internal Logger frames. Examples:
|
80
|
+
# * /ruby-2.4.0/lib/ruby/2.4.0/logger.rb
|
81
|
+
# * /gems/activesupport-4.2.7.1/lib/active_support/logger.rb
|
82
|
+
backtrace = notice[:errors].first[:backtrace]
|
83
|
+
notice[:errors].first[:backtrace] =
|
84
|
+
backtrace.drop_while { |frame| frame[:file] =~ %r{/logger.rb\z} }
|
85
|
+
|
86
|
+
notice[:context][:component] = 'log'
|
87
|
+
notice[:context][:severity] = normalize_severity(severity)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def normalize_severity(severity)
|
92
|
+
(case severity
|
93
|
+
when Logger::WARN then 'warning'
|
94
|
+
when Logger::ERROR, Logger::UNKNOWN then 'error'
|
95
|
+
when Logger::FATAL then 'critical'
|
96
|
+
else
|
97
|
+
raise "Unknown airbrake severity: #{severity}"
|
98
|
+
end).freeze
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'airbrake/rack/user'
|
2
|
+
require 'airbrake/rack/user_filter'
|
3
|
+
require 'airbrake/rack/context_filter'
|
4
|
+
require 'airbrake/rack/session_filter'
|
5
|
+
require 'airbrake/rack/http_params_filter'
|
6
|
+
require 'airbrake/rack/http_headers_filter'
|
7
|
+
require 'airbrake/rack/request_body_filter'
|
8
|
+
require 'airbrake/rack/route_filter'
|
9
|
+
require 'airbrake/rack/middleware'
|
10
|
+
require 'airbrake/rack/request_store'
|
11
|
+
require 'airbrake/rack/instrumentable'
|
12
|
+
|
13
|
+
module Airbrake
|
14
|
+
# Rack is a namespace for all Rack-related code.
|
15
|
+
module Rack
|
16
|
+
# @since v9.2.0
|
17
|
+
# @api public
|
18
|
+
def self.capture_timing(label)
|
19
|
+
routes = Airbrake::Rack::RequestStore[:routes]
|
20
|
+
if !routes || routes.none?
|
21
|
+
result = yield
|
22
|
+
else
|
23
|
+
timed_trace = Airbrake::TimedTrace.span(label) do
|
24
|
+
result = yield
|
25
|
+
end
|
26
|
+
|
27
|
+
routes.each do |_route_path, params|
|
28
|
+
params[:groups].merge!(timed_trace.spans)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
# Adds context (URL, User-Agent, framework version, controller and more).
|
4
|
+
#
|
5
|
+
# @since v5.7.0
|
6
|
+
class ContextFilter
|
7
|
+
# @return [Integer]
|
8
|
+
attr_reader :weight
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@weight = 99
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see Airbrake::FilterChain#refine
|
15
|
+
def call(notice)
|
16
|
+
return unless (request = notice.stash[:rack_request])
|
17
|
+
|
18
|
+
context = notice[:context]
|
19
|
+
|
20
|
+
context[:url] = request.url
|
21
|
+
context[:userAddr] = request.ip
|
22
|
+
context[:userAgent] = request.user_agent
|
23
|
+
|
24
|
+
add_framework_version(context)
|
25
|
+
|
26
|
+
controller = request.env['action_controller.instance']
|
27
|
+
return unless controller
|
28
|
+
|
29
|
+
context[:component] = controller.controller_name
|
30
|
+
context[:action] = controller.action_name
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def add_framework_version(context)
|
36
|
+
if context.key?(:versions)
|
37
|
+
context[:versions].merge!(framework_version)
|
38
|
+
else
|
39
|
+
context[:versions] = framework_version
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def framework_version
|
44
|
+
@framework_version ||=
|
45
|
+
if defined?(::Rails) && ::Rails.respond_to?(:version)
|
46
|
+
{ 'rails' => ::Rails.version }
|
47
|
+
elsif defined?(::Sinatra)
|
48
|
+
{ 'sinatra' => Sinatra::VERSION }
|
49
|
+
else
|
50
|
+
{
|
51
|
+
'rack_version' => ::Rack.version,
|
52
|
+
'rack_release' => ::Rack.release
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
# Adds HTTP request parameters.
|
4
|
+
#
|
5
|
+
# @since v5.7.0
|
6
|
+
class HttpHeadersFilter
|
7
|
+
# @return [Array<String>] the prefixes of the majority of HTTP headers in
|
8
|
+
# Rack (some prefixes match the header names for simplicity)
|
9
|
+
HTTP_HEADER_PREFIXES = [
|
10
|
+
'HTTP_'.freeze,
|
11
|
+
'CONTENT_TYPE'.freeze,
|
12
|
+
'CONTENT_LENGTH'.freeze
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
# @return [Integer]
|
16
|
+
attr_reader :weight
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@weight = 98
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see Airbrake::FilterChain#refine
|
23
|
+
def call(notice)
|
24
|
+
return unless (request = notice.stash[:rack_request])
|
25
|
+
|
26
|
+
http_headers = request.env.map.with_object({}) do |(key, value), headers|
|
27
|
+
if HTTP_HEADER_PREFIXES.any? { |prefix| key.to_s.start_with?(prefix) }
|
28
|
+
headers[key] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
headers
|
32
|
+
end
|
33
|
+
|
34
|
+
notice[:context].merge!(
|
35
|
+
httpMethod: request.request_method,
|
36
|
+
referer: request.referer,
|
37
|
+
headers: http_headers
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
# Adds HTTP request parameters.
|
4
|
+
#
|
5
|
+
# @since v5.7.0
|
6
|
+
class HttpParamsFilter
|
7
|
+
# @return [Integer]
|
8
|
+
attr_reader :weight
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@weight = 97
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see Airbrake::FilterChain#refine
|
15
|
+
def call(notice)
|
16
|
+
return unless (request = notice.stash[:rack_request])
|
17
|
+
|
18
|
+
notice[:params].merge!(request.params)
|
19
|
+
|
20
|
+
rails_params = request.env['action_dispatch.request.parameters']
|
21
|
+
notice[:params].merge!(rails_params) if rails_params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Airbrake
|
2
|
+
module Rack
|
3
|
+
# Instrumentable holds methods that simplify instrumenting Rack apps.
|
4
|
+
# @example
|
5
|
+
# class UsersController
|
6
|
+
# extend Airbrake::Rack::Instrumentable
|
7
|
+
#
|
8
|
+
# def index
|
9
|
+
# # ...
|
10
|
+
# end
|
11
|
+
# airbrake_capture_timing :index
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
# @since v9.2.0
|
16
|
+
module Instrumentable
|
17
|
+
def airbrake_capture_timing(method_name, label: method_name.to_s)
|
18
|
+
alias_method "#{method_name}_without_airbrake", method_name
|
19
|
+
|
20
|
+
define_method(method_name) do |*args|
|
21
|
+
Airbrake::Rack.capture_timing(label) do
|
22
|
+
__send__("#{method_name}_without_airbrake", *args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|