airbrake 3.1.6 → 11.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake.rb +23 -150
  3. data/lib/airbrake/capistrano.rb +6 -42
  4. data/lib/airbrake/capistrano/capistrano2.rb +40 -0
  5. data/lib/airbrake/capistrano/capistrano3.rb +23 -0
  6. data/lib/airbrake/delayed_job.rb +66 -0
  7. data/lib/airbrake/logger.rb +103 -0
  8. data/lib/airbrake/rack.rb +30 -45
  9. data/lib/airbrake/rack/context_filter.rb +65 -0
  10. data/lib/airbrake/rack/http_headers_filter.rb +44 -0
  11. data/lib/airbrake/rack/http_params_filter.rb +27 -0
  12. data/lib/airbrake/rack/instrumentable.rb +136 -0
  13. data/lib/airbrake/rack/middleware.rb +102 -0
  14. data/lib/airbrake/rack/request_body_filter.rb +33 -0
  15. data/lib/airbrake/rack/request_store.rb +34 -0
  16. data/lib/airbrake/rack/route_filter.rb +51 -0
  17. data/lib/airbrake/rack/session_filter.rb +25 -0
  18. data/lib/airbrake/rack/user.rb +74 -0
  19. data/lib/airbrake/rack/user_filter.rb +25 -0
  20. data/lib/airbrake/rails.rb +25 -31
  21. data/lib/airbrake/rails/action_cable.rb +35 -0
  22. data/lib/airbrake/rails/action_cable/notify_callback.rb +22 -0
  23. data/lib/airbrake/rails/action_controller.rb +40 -0
  24. data/lib/airbrake/rails/action_controller_notify_subscriber.rb +32 -0
  25. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +51 -0
  26. data/lib/airbrake/rails/action_controller_route_subscriber.rb +33 -0
  27. data/lib/airbrake/rails/active_job.rb +50 -0
  28. data/lib/airbrake/rails/active_record.rb +36 -0
  29. data/lib/airbrake/rails/active_record_subscriber.rb +46 -0
  30. data/lib/airbrake/rails/app.rb +78 -0
  31. data/lib/airbrake/rails/backtrace_cleaner.rb +23 -0
  32. data/lib/airbrake/rails/curb.rb +32 -0
  33. data/lib/airbrake/rails/event.rb +81 -0
  34. data/lib/airbrake/rails/excon_subscriber.rb +25 -0
  35. data/lib/airbrake/rails/http.rb +14 -0
  36. data/lib/airbrake/rails/http_client.rb +16 -0
  37. data/lib/airbrake/rails/net_http.rb +18 -0
  38. data/lib/airbrake/rails/railtie.rb +151 -0
  39. data/lib/airbrake/rails/typhoeus.rb +16 -0
  40. data/lib/airbrake/rake.rb +65 -0
  41. data/lib/airbrake/rake/tasks.rb +112 -0
  42. data/lib/airbrake/resque.rb +61 -0
  43. data/lib/airbrake/shoryuken.rb +54 -0
  44. data/lib/airbrake/sidekiq.rb +55 -0
  45. data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +53 -0
  46. data/lib/airbrake/sneakers.rb +72 -0
  47. data/lib/airbrake/version.rb +5 -1
  48. data/lib/generators/airbrake_generator.rb +25 -0
  49. data/lib/generators/airbrake_initializer.rb.erb +80 -0
  50. metadata +206 -259
  51. data/CHANGELOG +0 -944
  52. data/Gemfile +0 -3
  53. data/Guardfile +0 -6
  54. data/INSTALL +0 -20
  55. data/MIT-LICENSE +0 -22
  56. data/README.md +0 -556
  57. data/README_FOR_HEROKU_ADDON.md +0 -94
  58. data/Rakefile +0 -223
  59. data/SUPPORTED_RAILS_VERSIONS +0 -38
  60. data/TESTING.md +0 -41
  61. data/airbrake.gemspec +0 -40
  62. data/bin/airbrake +0 -12
  63. data/features/metal.feature +0 -18
  64. data/features/rack.feature +0 -60
  65. data/features/rails.feature +0 -272
  66. data/features/rails_with_js_notifier.feature +0 -97
  67. data/features/rake.feature +0 -27
  68. data/features/sinatra.feature +0 -29
  69. data/features/step_definitions/file_steps.rb +0 -10
  70. data/features/step_definitions/metal_steps.rb +0 -23
  71. data/features/step_definitions/rack_steps.rb +0 -23
  72. data/features/step_definitions/rails_application_steps.rb +0 -478
  73. data/features/step_definitions/rake_steps.rb +0 -17
  74. data/features/support/airbrake_shim.rb.template +0 -16
  75. data/features/support/env.rb +0 -18
  76. data/features/support/matchers.rb +0 -35
  77. data/features/support/rails.rb +0 -201
  78. data/features/support/rake/Rakefile +0 -68
  79. data/features/support/terminal.rb +0 -107
  80. data/features/user_informer.feature +0 -63
  81. data/generators/airbrake/airbrake_generator.rb +0 -94
  82. data/generators/airbrake/lib/insert_commands.rb +0 -34
  83. data/generators/airbrake/lib/rake_commands.rb +0 -24
  84. data/generators/airbrake/templates/airbrake_tasks.rake +0 -25
  85. data/generators/airbrake/templates/capistrano_hook.rb +0 -6
  86. data/generators/airbrake/templates/initializer.rb +0 -6
  87. data/install.rb +0 -1
  88. data/lib/airbrake/backtrace.rb +0 -108
  89. data/lib/airbrake/cli/client.rb +0 -68
  90. data/lib/airbrake/cli/options.rb +0 -41
  91. data/lib/airbrake/cli/printer.rb +0 -30
  92. data/lib/airbrake/cli/project.rb +0 -17
  93. data/lib/airbrake/cli/project_factory.rb +0 -36
  94. data/lib/airbrake/cli/runner.rb +0 -48
  95. data/lib/airbrake/cli/validator.rb +0 -8
  96. data/lib/airbrake/configuration.rb +0 -311
  97. data/lib/airbrake/extensions/blank.rb +0 -73
  98. data/lib/airbrake/notice.rb +0 -390
  99. data/lib/airbrake/rails/action_controller_catcher.rb +0 -30
  100. data/lib/airbrake/rails/controller_methods.rb +0 -87
  101. data/lib/airbrake/rails/error_lookup.rb +0 -33
  102. data/lib/airbrake/rails/javascript_notifier.rb +0 -47
  103. data/lib/airbrake/rails/middleware/exceptions_catcher.rb +0 -33
  104. data/lib/airbrake/rails3_tasks.rb +0 -98
  105. data/lib/airbrake/railtie.rb +0 -48
  106. data/lib/airbrake/rake_handler.rb +0 -71
  107. data/lib/airbrake/sender.rb +0 -128
  108. data/lib/airbrake/shared_tasks.rb +0 -47
  109. data/lib/airbrake/tasks.rb +0 -83
  110. data/lib/airbrake/user_informer.rb +0 -27
  111. data/lib/airbrake_tasks.rb +0 -64
  112. data/lib/rails/generators/airbrake/airbrake_generator.rb +0 -100
  113. data/lib/templates/javascript_notifier.erb +0 -15
  114. data/lib/templates/rescue.erb +0 -91
  115. data/rails/init.rb +0 -1
  116. data/resources/README.md +0 -34
  117. data/resources/ca-bundle.crt +0 -3376
  118. data/script/integration_test.rb +0 -38
  119. data/test/airbrake_2_3.xsd +0 -88
  120. data/test/airbrake_tasks_test.rb +0 -170
  121. data/test/backtrace_test.rb +0 -162
  122. data/test/capistrano_test.rb +0 -34
  123. data/test/catcher_test.rb +0 -333
  124. data/test/configuration_test.rb +0 -233
  125. data/test/helper.rb +0 -263
  126. data/test/javascript_notifier_test.rb +0 -51
  127. data/test/logger_test.rb +0 -79
  128. data/test/notice_test.rb +0 -490
  129. data/test/notifier_test.rb +0 -276
  130. data/test/rack_test.rb +0 -58
  131. data/test/rails_initializer_test.rb +0 -36
  132. data/test/recursion_test.rb +0 -10
  133. data/test/sender_test.rb +0 -288
  134. data/test/user_informer_test.rb +0 -29
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 81da57e8a5a47cfafd0a69d4d4c89e100301ba4c5e48418866ce584a95fe3632
4
+ data.tar.gz: c24d6f44c8eae4ad946471098620b16c6973d9272b0363f2420305b35374b7a2
5
+ SHA512:
6
+ metadata.gz: 95b80ba3b1bf3771695c22fc28511a44347a4c8b841fc51d80f5abe14eb204147502f22599c2663a69f8b95986e1dd0cc7c026983957ecedb1761df4ab4311f5
7
+ data.tar.gz: 0dc035ee0b9b791eb13b2b7be401e46b5ab4fb5b906f5b180123b4bd9d4e3fd3a83439ffafe29e0371e39e71697575b0790992e5f240349b5113ad26a47b1dbf
@@ -1,159 +1,32 @@
1
- require "girl_friday"
2
- require 'net/http'
3
- require 'net/https'
4
- require 'rubygems'
5
- require 'airbrake/extensions/blank'
6
- require 'airbrake/version'
7
- require 'airbrake/configuration'
8
- require 'airbrake/notice'
9
- require 'airbrake/sender'
10
- require 'airbrake/backtrace'
11
- require 'airbrake/rack'
12
- require 'airbrake/user_informer'
13
-
14
- require 'airbrake/railtie' if defined?(Rails::Railtie)
15
-
16
- module Airbrake
17
- API_VERSION = "2.3"
18
- LOG_PREFIX = "** [Airbrake] "
19
-
20
- HEADERS = {
21
- 'Content-type' => 'text/xml',
22
- 'Accept' => 'text/xml, application/xml'
23
- }
24
-
25
- class << self
26
- # The sender object is responsible for delivering formatted data to the Airbrake server.
27
- # Must respond to #send_to_airbrake. See Airbrake::Sender.
28
- attr_accessor :sender
29
-
30
- # A Airbrake configuration object. Must act like a hash and return sensible
31
- # values for all Airbrake configuration options. See Airbrake::Configuration.
32
- attr_writer :configuration
33
-
34
- # Tell the log that the Notifier is good to go
35
- def report_ready
36
- write_verbose_log("Notifier #{VERSION} ready to catch errors")
37
- end
38
-
39
- # Prints out the environment info to the log for debugging help
40
- def report_environment_info
41
- write_verbose_log("Environment Info: #{environment_info}")
42
- end
43
-
44
- # Prints out the response body from Airbrake for debugging help
45
- def report_response_body(response)
46
- write_verbose_log("Response from Airbrake: \n#{response}")
47
- end
48
-
49
- # Prints out the details about the notice that wasn't sent to server
50
- def report_notice(notice)
51
- write_verbose_log("Notice details: \n#{notice}")
52
- end
1
+ # frozen_string_literal: true
53
2
 
54
- # Returns the Ruby version, Rails version, and current Rails environment
55
- def environment_info
56
- info = "[Ruby: #{RUBY_VERSION}]"
57
- info << " [#{configuration.framework}]" if configuration.framework
58
- info << " [Env: #{configuration.environment_name}]" if configuration.environment_name
59
- end
3
+ require 'shellwords'
4
+ require 'English'
60
5
 
61
- # Writes out the given message to the #logger
62
- def write_verbose_log(message)
63
- logger.debug LOG_PREFIX + message if logger
64
- end
6
+ # Core library that sends notices.
7
+ # See: https://github.com/airbrake/airbrake-ruby
8
+ require 'airbrake-ruby'
65
9
 
66
- # Look for the Rails logger currently defined
67
- def logger
68
- self.configuration.logger
69
- end
70
-
71
- # Call this method to modify defaults in your initializers.
72
- #
73
- # @example
74
- # Airbrake.configure do |config|
75
- # config.api_key = '1234567890abcdef'
76
- # config.secure = false
77
- # end
78
- def configure(silent = false)
79
- yield(configuration)
80
- self.sender = Sender.new(configuration)
81
- report_ready unless silent
82
- self.sender
83
- end
84
-
85
- # The configuration object.
86
- # @see Airbrake.configure
87
- def configuration
88
- @configuration ||= Configuration.new
89
- end
90
-
91
- # Sends an exception manually using this method, even when you are not in a controller.
92
- #
93
- # @param [Exception] exception The exception you want to notify Airbrake about.
94
- # @param [Hash] opts Data that will be sent to Airbrake.
95
- #
96
- # @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Airbrake uses for identification.
97
- # @option opts [String] :error_message The error returned by the exception (or the message you want to log).
98
- # @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
99
- # @option opts [String] :rack_env The Rack environment.
100
- # @option opts [String] :session The contents of the user's session.
101
- # @option opts [String] :environment_name The application environment name.
102
- def notify(exception, opts = {})
103
- send_notice(build_notice_for(exception, opts))
104
- end
105
-
106
- # Sends the notice unless it is one of the default ignored exceptions
107
- # @see Airbrake.notify
108
- def notify_or_ignore(exception, opts = {})
109
- notice = build_notice_for(exception, opts)
110
- send_notice(notice) unless notice.ignore?
111
- end
112
-
113
- def build_lookup_hash_for(exception, options = {})
114
- notice = build_notice_for(exception, options)
115
-
116
- result = {}
117
- result[:action] = notice.action rescue nil
118
- result[:component] = notice.component rescue nil
119
- result[:error_class] = notice.error_class if notice.error_class
120
- result[:environment_name] = 'production'
121
-
122
- unless notice.backtrace.lines.empty?
123
- result[:file] = notice.backtrace.lines.first.file
124
- result[:line_number] = notice.backtrace.lines.first.number
125
- end
10
+ require 'airbrake/version'
126
11
 
127
- result
128
- end
12
+ # Automatically load needed files for the environment the library is running in.
13
+ if defined?(Rack)
14
+ require 'airbrake/rack'
129
15
 
130
- private
16
+ require 'airbrake/rails' if defined?(Rails)
17
+ end
131
18
 
132
- def send_notice(notice)
133
- if configuration.public?
134
- if configuration.async?
135
- configuration.async.call(notice)
136
- else
137
- sender.send_to_airbrake(notice)
138
- end
139
- end
140
- end
19
+ require 'airbrake/rake' if defined?(Rake::Task)
20
+ require 'airbrake/resque' if defined?(Resque)
21
+ require 'airbrake/sidekiq' if defined?(Sidekiq)
22
+ require 'airbrake/shoryuken' if defined?(Shoryuken)
23
+ require 'airbrake/delayed_job' if defined?(Delayed)
24
+ require 'airbrake/sneakers' if defined?(Sneakers)
141
25
 
142
- def build_notice_for(exception, opts = {})
143
- exception = unwrap_exception(exception)
144
- opts = opts.merge(:exception => exception) if exception.is_a?(Exception)
145
- opts = opts.merge(exception.to_hash) if exception.respond_to?(:to_hash)
146
- Notice.new(configuration.merge(opts))
147
- end
26
+ require 'airbrake/logger'
148
27
 
149
- def unwrap_exception(exception)
150
- if exception.respond_to?(:original_exception)
151
- exception.original_exception
152
- elsif exception.respond_to?(:continued_exception)
153
- exception.continued_exception
154
- else
155
- exception
156
- end
157
- end
158
- end
28
+ # Notify of unhandled exceptions, if there were any, but ignore SystemExit.
29
+ at_exit do
30
+ Airbrake.notify_sync($ERROR_INFO) if $ERROR_INFO
31
+ Airbrake.close
159
32
  end
@@ -1,44 +1,8 @@
1
- # Defines deploy:notify_airbrake which will send information about the deploy to Airbrake.
2
- require 'capistrano'
1
+ # frozen_string_literal: true
3
2
 
4
- module Airbrake
5
- module Capistrano
6
- def self.load_into(configuration)
7
- configuration.load do
8
- after "deploy", "airbrake:deploy"
9
- after "deploy:migrations", "airbrake:deploy"
10
- after "deploy:cold", "airbrake:deploy"
11
-
12
- namespace :airbrake do
13
- desc <<-DESC
14
- Notify Airbrake of the deployment by running the notification on the REMOTE machine.
15
- - Run remotely so we use remote API keys, environment, etc.
16
- DESC
17
- task :deploy, :except => { :no_release => true } do
18
- rails_env = fetch(:rails_env, "production")
19
- airbrake_env = fetch(:airbrake_env, fetch(:rails_env, "production"))
20
- local_user = ENV['USER'] || ENV['USERNAME']
21
- executable = RUBY_PLATFORM.downcase.include?('mswin') ? fetch(:rake, 'rake.bat') : fetch(:rake, 'rake')
22
- directory = configuration.current_release
23
- notify_command = "cd #{directory}; #{executable} RAILS_ENV=#{rails_env} airbrake:deploy TO=#{airbrake_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
24
- notify_command << " DRY_RUN=true" if dry_run
25
- notify_command << " API_KEY=#{ENV['API_KEY']}" if ENV['API_KEY']
26
- logger.info "Notifying Airbrake of Deploy (#{notify_command})"
27
- if configuration.dry_run
28
- logger.info "DRY RUN: Notification not actually run."
29
- else
30
- result = ""
31
- run(notify_command, :once => true) { |ch, stream, data| result << data }
32
- # TODO: Check if SSL is active on account via result content.
33
- end
34
- logger.info "Airbrake Notification Complete."
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
41
-
42
- if Capistrano::Configuration.instance
43
- Airbrake::Capistrano.load_into(Capistrano::Configuration.instance)
3
+ if defined?(Capistrano::VERSION) &&
4
+ Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
5
+ require 'airbrake/capistrano/capistrano3'
6
+ else
7
+ require 'airbrake/capistrano/capistrano2'
44
8
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ # The Capistrano v2 integration.
5
+ module Capistrano
6
+ # rubocop:disable Metrics/AbcSize
7
+ def self.load_into(config)
8
+ config.load do
9
+ after 'deploy', 'airbrake:deploy'
10
+ after 'deploy:migrations', 'airbrake:deploy'
11
+ after 'deploy:cold', 'airbrake:deploy'
12
+
13
+ namespace :airbrake do
14
+ desc "Notify Airbrake of the deploy"
15
+ task :deploy, except: { no_release: true }, on_error: :continue do
16
+ run(
17
+ <<-CMD, once: true
18
+ cd #{config.release_path} && \
19
+
20
+ RACK_ENV=#{fetch(:rack_env, nil)} \
21
+ RAILS_ENV=#{fetch(:rails_env, nil)} \
22
+
23
+ bundle exec rake airbrake:deploy \
24
+ USERNAME=#{Shellwords.shellescape(ENV['USER'] || ENV['USERNAME'])} \
25
+ ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, 'production'))} \
26
+ REVISION=#{current_revision.strip} \
27
+ REPOSITORY=#{repository} \
28
+ VERSION=#{fetch(:app_version, nil)}
29
+ CMD
30
+ )
31
+ logger.info 'Notified Airbrake of the deploy'
32
+ end
33
+ end
34
+ end
35
+ end
36
+ # rubocop:enable Metrics/AbcSize
37
+ end
38
+ end
39
+
40
+ Airbrake::Capistrano.load_into(Capistrano::Configuration.instance)
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :airbrake do
4
+ desc "Notify Airbrake of the deploy"
5
+ task :deploy do
6
+ role = roles(:all, select: :primary).first || roles(:all).first
7
+ on role do
8
+ within release_path do
9
+ with rails_env: fetch(:rails_env, fetch(:stage)) do
10
+ execute :bundle, :exec, :rake, <<-CMD
11
+ airbrake:deploy USERNAME=#{Shellwords.shellescape(local_user)} \
12
+ ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, fetch(:stage)))} \
13
+ REVISION=#{fetch(:current_revision)} \
14
+ REPOSITORY=#{fetch(:repo_url)} \
15
+ VERSION=#{fetch(:app_version)}
16
+ CMD
17
+
18
+ info 'Notified Airbrake of the deploy'
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Delayed
4
+ module Plugins
5
+ # Provides integration with Delayed Job.
6
+ # rubocop:disable Metrics/BlockLength
7
+ class Airbrake < ::Delayed::Plugin
8
+ callbacks do |lifecycle|
9
+ lifecycle.around(:invoke_job) do |job, *args, &block|
10
+ begin
11
+ timing = ::Airbrake::Benchmark.measure do
12
+ # Forward the call to the next callback in the callback chain
13
+ block.call(job, *args)
14
+ end
15
+ rescue Exception => exception # rubocop:disable Lint/RescueException
16
+ params = job.as_json
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
+ job_class = job.payload_object.job_data['job_class']
22
+ end
23
+
24
+ action = job_class || job.payload_object.class.name
25
+
26
+ ::Airbrake.notify(exception, params) do |notice|
27
+ notice[:context][:component] = 'delayed_job'
28
+ notice[:context][:action] = action
29
+ end
30
+
31
+ ::Airbrake.notify_queue(
32
+ queue: action,
33
+ error_count: 1,
34
+ timing: 0.01,
35
+ )
36
+
37
+ raise exception
38
+ else
39
+ ::Airbrake.notify_queue(
40
+ queue: job_class || job.payload_object.class.name,
41
+ error_count: 0,
42
+ timing: timing,
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
48
+ # rubocop:enable Metrics/BlockLength
49
+ end
50
+ end
51
+
52
+ if RUBY_ENGINE == 'jruby' && defined?(Delayed::Backend::ActiveRecord::Job)
53
+ # Workaround against JRuby bug:
54
+ # https://github.com/jruby/jruby/issues/3338
55
+ # rubocop:disable Style/ClassAndModuleChildren
56
+ class Delayed::Backend::ActiveRecord::Job
57
+ alias old_to_ary to_ary
58
+
59
+ def to_ary
60
+ old_to_ary || [self]
61
+ end
62
+ end
63
+ # rubocop:enable Style/ClassAndModuleChildren
64
+ end
65
+
66
+ Delayed::Worker.plugins << Delayed::Plugins::Airbrake
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'delegate'
5
+
6
+ module Airbrake
7
+ # Decorator for +Logger+ from stdlib. Endows loggers the ability to both log
8
+ # and report errors to Airbrake.
9
+ #
10
+ # @example
11
+ # # Create a logger like you normally do and decorate it.
12
+ # logger = Airbrake::AirbrakeLogger.new(Logger.new(STDOUT))
13
+ #
14
+ # # Just use the logger like you normally do.
15
+ # logger.fatal('oops')
16
+ class AirbrakeLogger < SimpleDelegator
17
+ # @example
18
+ # # Assign a custom Airbrake notifier
19
+ # logger.airbrake_notifier = Airbrake::NoticeNotifier.new
20
+ # @return [Airbrake::Notifier] notifier to be used to send notices
21
+ attr_accessor :airbrake_notifier
22
+
23
+ # @return [Integer]
24
+ attr_reader :airbrake_level
25
+
26
+ def initialize(logger)
27
+ __setobj__(logger)
28
+ @airbrake_notifier = Airbrake
29
+ self.level = logger.level
30
+ end
31
+
32
+ # @see Logger#warn
33
+ def warn(progname = nil, &block)
34
+ notify_airbrake(Logger::WARN, progname)
35
+ super
36
+ end
37
+
38
+ # @see Logger#error
39
+ def error(progname = nil, &block)
40
+ notify_airbrake(Logger::ERROR, progname)
41
+ super
42
+ end
43
+
44
+ # @see Logger#fatal
45
+ def fatal(progname = nil, &block)
46
+ notify_airbrake(Logger::FATAL, progname)
47
+ super
48
+ end
49
+
50
+ # @see Logger#unknown
51
+ def unknown(progname = nil, &block)
52
+ notify_airbrake(Logger::UNKNOWN, progname)
53
+ super
54
+ end
55
+
56
+ # @see Logger#level=
57
+ def level=(value)
58
+ self.airbrake_level = value < Logger::WARN ? Logger::WARN : value
59
+ super
60
+ end
61
+
62
+ # Sets airbrake severity level. Does not permit values below `Logger::WARN`.
63
+ #
64
+ # @example
65
+ # logger.airbrake_level = Logger::FATAL
66
+ # @return [void]
67
+ def airbrake_level=(level)
68
+ if level < Logger::WARN
69
+ raise "Airbrake severity level #{level} is not allowed. " \
70
+ "Minimum allowed level is #{Logger::WARN}"
71
+ end
72
+ @airbrake_level = level
73
+ end
74
+
75
+ private
76
+
77
+ def notify_airbrake(severity, progname)
78
+ return if severity < @airbrake_level || !@airbrake_notifier
79
+
80
+ @airbrake_notifier.notify(progname) do |notice|
81
+ # Get rid of unwanted internal Logger frames. Examples:
82
+ # * /ruby-2.4.0/lib/ruby/2.4.0/logger.rb
83
+ # * /gems/activesupport-4.2.7.1/lib/active_support/logger.rb
84
+ backtrace = notice[:errors].first[:backtrace]
85
+ notice[:errors].first[:backtrace] =
86
+ backtrace.drop_while { |frame| frame[:file] =~ %r{/logger.rb\z} }
87
+
88
+ notice[:context][:component] = 'log'
89
+ notice[:context][:severity] = normalize_severity(severity)
90
+ end
91
+ end
92
+
93
+ def normalize_severity(severity)
94
+ (case severity
95
+ when Logger::WARN then 'warning'
96
+ when Logger::ERROR, Logger::UNKNOWN then 'error'
97
+ when Logger::FATAL then 'critical'
98
+ else
99
+ raise "Unknown airbrake severity: #{severity}"
100
+ end).freeze
101
+ end
102
+ end
103
+ end