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