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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake.rb +30 -0
  3. data/lib/airbrake/capistrano.rb +6 -0
  4. data/lib/airbrake/capistrano/capistrano2.rb +38 -0
  5. data/lib/airbrake/capistrano/capistrano3.rb +21 -0
  6. data/lib/airbrake/delayed_job.rb +48 -0
  7. data/lib/airbrake/logger.rb +101 -0
  8. data/lib/airbrake/rack.rb +35 -0
  9. data/lib/airbrake/rack/context_filter.rb +58 -0
  10. data/lib/airbrake/rack/http_headers_filter.rb +42 -0
  11. data/lib/airbrake/rack/http_params_filter.rb +25 -0
  12. data/lib/airbrake/rack/instrumentable.rb +28 -0
  13. data/lib/airbrake/rack/middleware.rb +100 -0
  14. data/lib/airbrake/rack/request_body_filter.rb +31 -0
  15. data/lib/airbrake/rack/request_store.rb +32 -0
  16. data/lib/airbrake/rack/route_filter.rb +53 -0
  17. data/lib/airbrake/rack/session_filter.rb +23 -0
  18. data/lib/airbrake/rack/user.rb +70 -0
  19. data/lib/airbrake/rack/user_filter.rb +23 -0
  20. data/lib/airbrake/rails.rb +32 -0
  21. data/lib/airbrake/rails/action_cable.rb +33 -0
  22. data/lib/airbrake/rails/action_cable/notify_callback.rb +20 -0
  23. data/lib/airbrake/rails/action_controller.rb +35 -0
  24. data/lib/airbrake/rails/action_controller_notify_subscriber.rb +28 -0
  25. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +46 -0
  26. data/lib/airbrake/rails/action_controller_route_subscriber.rb +46 -0
  27. data/lib/airbrake/rails/active_job.rb +33 -0
  28. data/lib/airbrake/rails/active_record.rb +34 -0
  29. data/lib/airbrake/rails/active_record_subscriber.rb +42 -0
  30. data/lib/airbrake/rails/app.rb +43 -0
  31. data/lib/airbrake/rails/backtrace_cleaner.rb +10 -0
  32. data/lib/airbrake/rails/curb.rb +35 -0
  33. data/lib/airbrake/rails/event.rb +83 -0
  34. data/lib/airbrake/rails/excon_subscriber.rb +21 -0
  35. data/lib/airbrake/rails/http.rb +12 -0
  36. data/lib/airbrake/rails/http_client.rb +10 -0
  37. data/lib/airbrake/rails/net_http.rb +10 -0
  38. data/lib/airbrake/rails/railtie.rb +141 -0
  39. data/lib/airbrake/rails/typhoeus.rb +12 -0
  40. data/lib/airbrake/rake.rb +63 -0
  41. data/lib/airbrake/rake/tasks.rb +110 -0
  42. data/lib/airbrake/resque.rb +29 -0
  43. data/lib/airbrake/shoryuken.rb +40 -0
  44. data/lib/airbrake/sidekiq.rb +47 -0
  45. data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +51 -0
  46. data/lib/airbrake/sneakers.rb +34 -0
  47. data/lib/airbrake/version.rb +5 -0
  48. data/lib/generators/airbrake_generator.rb +23 -0
  49. data/lib/generators/airbrake_initializer.rb.erb +78 -0
  50. metadata +416 -0
@@ -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'
@@ -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,6 @@
1
+ if defined?(Capistrano::VERSION) &&
2
+ Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
3
+ require 'airbrake/capistrano/capistrano3'
4
+ else
5
+ require 'airbrake/capistrano/capistrano2'
6
+ 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