airbrake 9.5.5 → 10.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90f7f39f6012a7e8383f50d1d99c8631582032feddaaa5a452bb7ba9afc40fc6
4
- data.tar.gz: 728831ea6a9a57815fec54ac507f4712923bcfe5b012b31658ddd0c1b4d576ba
3
+ metadata.gz: 83054730bd07260d0293206623452abacfc4b0006f65900811bac214a026c8a0
4
+ data.tar.gz: dee0bf02404e401d98b065e0550cffb4fb8bdec9e208cb31d4e37155a4b9e29c
5
5
  SHA512:
6
- metadata.gz: d899543189d807cbc393fba4643274eea3b02134fa09aec828926dc2dced70adef3071b36092fa0f3ba9809217b3c74aa8e6d25849c22cfcc88640a6d257c85b
7
- data.tar.gz: ca0c24bbd41fdd983a128763c99a3ce43aef445266d71606d54263782894e9a4987dde638c08083eb037ae6cae322d51ba1f42e4b690422478f4c3550cec817b
6
+ metadata.gz: b62c7face7778e77164b5f5222c64b6623984e2925a5b1928de2eb9a5b15a224111aa87b427cdb79b6626e0ae0bee0fc2d59b0780bfc6e5d852f227d4ed4679b
7
+ data.tar.gz: 41407ade81d73fb1594c67ebd26311f69d3888445fa8b28ae23a0a48031a323dc9ac4a68dc6a9906b532e0855b2878edf9712565b5ef458ec2e9250d59864c2f
@@ -1,14 +1,16 @@
1
1
  module Delayed
2
2
  module Plugins
3
3
  # Provides integration with Delayed Job.
4
- # rubocop:disable Lint/RescueException
4
+ # rubocop:disable Metrics/BlockLength
5
5
  class Airbrake < ::Delayed::Plugin
6
6
  callbacks do |lifecycle|
7
7
  lifecycle.around(:invoke_job) do |job, *args, &block|
8
8
  begin
9
- # Forward the call to the next callback in the callback chain
10
- block.call(job, *args)
11
- rescue Exception => exception
9
+ timing = ::Airbrake::Benchmark.measure do
10
+ # Forward the call to the next callback in the callback chain
11
+ block.call(job, *args)
12
+ end
13
+ rescue Exception => exception # rubocop:disable Lint/RescueException
12
14
  params = job.as_json
13
15
 
14
16
  # If DelayedJob is used through ActiveJob, it contains extra info.
@@ -17,17 +19,31 @@ module Delayed
17
19
  job_class = job.payload_object.job_data['job_class']
18
20
  end
19
21
 
22
+ action = job_class || job.payload_object.class.name
23
+
20
24
  ::Airbrake.notify(exception, params) do |notice|
21
25
  notice[:context][:component] = 'delayed_job'
22
- notice[:context][:action] = job_class || job.payload_object.class.name
26
+ notice[:context][:action] = action
23
27
  end
24
28
 
29
+ ::Airbrake.notify_queue_sync(
30
+ queue: action,
31
+ error_count: 1,
32
+ timing: 0.01,
33
+ )
34
+
25
35
  raise exception
36
+ else
37
+ ::Airbrake.notify_queue_sync(
38
+ queue: job_class || job.payload_object.class.name,
39
+ error_count: 0,
40
+ timing: timing,
41
+ )
26
42
  end
27
43
  end
28
44
  end
29
45
  end
30
- # rubocop:enable Lint/RescueException
46
+ # rubocop:enable Metrics/BlockLength
31
47
  end
32
48
  end
33
49
 
@@ -18,7 +18,12 @@ module Airbrake
18
18
  context = notice[:context]
19
19
 
20
20
  context[:url] = request.url
21
- context[:userAddr] = request.ip
21
+ context[:userAddr] =
22
+ if request.respond_to?(:remote_ip)
23
+ request.remote_ip
24
+ else
25
+ request.ip
26
+ end
22
27
  context[:userAgent] = request.user_agent
23
28
 
24
29
  add_framework_version(context)
@@ -49,7 +54,7 @@ module Airbrake
49
54
  else
50
55
  {
51
56
  'rack_version' => ::Rack.version,
52
- 'rack_release' => ::Rack.release
57
+ 'rack_release' => ::Rack.release,
53
58
  }
54
59
  end
55
60
  end
@@ -9,7 +9,7 @@ module Airbrake
9
9
  HTTP_HEADER_PREFIXES = [
10
10
  'HTTP_'.freeze,
11
11
  'CONTENT_TYPE'.freeze,
12
- 'CONTENT_LENGTH'.freeze
12
+ 'CONTENT_LENGTH'.freeze,
13
13
  ].freeze
14
14
 
15
15
  # @return [Integer]
@@ -34,7 +34,7 @@ module Airbrake
34
34
  notice[:context].merge!(
35
35
  httpMethod: request.request_method,
36
36
  referer: request.referer,
37
- headers: http_headers
37
+ headers: http_headers,
38
38
  )
39
39
  end
40
40
  end
@@ -94,7 +94,7 @@ end
94
94
  Airbrake::Rack::SessionFilter,
95
95
  Airbrake::Rack::HttpParamsFilter,
96
96
  Airbrake::Rack::HttpHeadersFilter,
97
- Airbrake::Rack::RouteFilter
97
+ Airbrake::Rack::RouteFilter,
98
98
  ].each do |filter|
99
99
  Airbrake.add_filter(filter.new)
100
100
  end
@@ -12,7 +12,7 @@ module Airbrake
12
12
 
13
13
  # Rails.logger is not set in some Rake tasks such as
14
14
  # 'airbrake:deploy'. In this case we use a sensible fallback.
15
- level: (::Rails.logger ? ::Rails.logger.level : Logger::ERROR)
15
+ level: (::Rails.logger ? ::Rails.logger.level : Logger::ERROR),
16
16
  )
17
17
  end
18
18
  end
@@ -18,8 +18,8 @@ module Airbrake
18
18
  method: event.method,
19
19
  route: route,
20
20
  status_code: event.status_code,
21
- start_time: event.time,
22
- end_time: Time.new
21
+ timing: event.duration,
22
+ time: event.time,
23
23
  )
24
24
  end
25
25
  end
@@ -20,7 +20,8 @@ module Airbrake
20
20
  route: route,
21
21
  response_type: event.response_type,
22
22
  groups: groups,
23
- start_time: event.time
23
+ timing: event.duration,
24
+ time: event.time,
24
25
  }
25
26
 
26
27
  Airbrake.notify_performance_breakdown(breakdown_info, stash)
@@ -14,14 +14,14 @@ module Airbrake
14
14
 
15
15
  event = Airbrake::Rails::Event.new(*args)
16
16
  route = Airbrake::Rails::App.recognize_route(
17
- Airbrake::Rack::RequestStore[:request]
17
+ Airbrake::Rack::RequestStore[:request],
18
18
  )
19
19
  return unless route
20
20
 
21
21
  routes[route.path] = {
22
22
  method: event.method,
23
23
  response_type: event.response_type,
24
- groups: {}
24
+ groups: {},
25
25
  }
26
26
  end
27
27
  end
@@ -23,10 +23,33 @@ module Airbrake
23
23
  raise exception
24
24
  end
25
25
 
26
+ def self.perform(job, block)
27
+ timing = Airbrake::Benchmark.measure do
28
+ block.call
29
+ end
30
+ rescue StandardError => exception
31
+ Airbrake.notify_queue_sync(
32
+ queue: job.class.name,
33
+ error_count: 1,
34
+ timing: 0.01,
35
+ )
36
+ raise exception
37
+ else
38
+ Airbrake.notify_queue_sync(
39
+ queue: job.class.name,
40
+ error_count: 0,
41
+ timing: timing,
42
+ )
43
+ end
44
+
26
45
  included do
27
46
  rescue_from(Exception) do |exception|
28
47
  Airbrake::Rails::ActiveJob.notify_airbrake(exception, self)
29
48
  end
49
+
50
+ around_perform do |job, block|
51
+ Airbrake::Rails::ActiveJob.perform(job, block)
52
+ end
30
53
  end
31
54
  end
32
55
  end
@@ -22,8 +22,8 @@ module Airbrake
22
22
  func: frame[:function],
23
23
  file: frame[:file],
24
24
  line: frame[:line],
25
- start_time: event.time,
26
- end_time: event.end
25
+ timing: event.duration,
26
+ time: event.time,
27
27
  )
28
28
  end
29
29
  end
@@ -33,7 +33,7 @@ module Airbrake
33
33
  def last_caller
34
34
  exception = StandardError.new
35
35
  exception.set_backtrace(
36
- Airbrake::Rails::BacktraceCleaner.clean(Kernel.caller)
36
+ Airbrake::Rails::BacktraceCleaner.clean(Kernel.caller),
37
37
  )
38
38
  Airbrake::Backtrace.parse(exception).first || {}
39
39
  end
@@ -13,26 +13,42 @@ module Airbrake
13
13
  # Duplicate `request` because `recognize` *can* strip the request's
14
14
  # `path_info`, which results in broken engine links (when the engine has
15
15
  # an isolated namespace).
16
- ::Rails.application.routes.router.recognize(request.dup) do |route, _params|
17
- path =
18
- if route.app.respond_to?(:app) && route.app.app.respond_to?(:engine_name)
19
- "#{route.app.app.engine_name}##{route.path.spec}"
20
- else
21
- route.path.spec.to_s
22
- end
16
+ request_copy = request.dup
23
17
 
24
- # Rails can recognize multiple routes for the given request. For
25
- # example, if we visit /users/2/edit, then Rails sees these routes:
26
- # * "/users/:id/edit(.:format)"
27
- # * "/"
28
- #
29
- # We return the first route as, what it seems, the most optimal
30
- # approach.
31
- return Route.new(path)
18
+ # We must search every engine individually to find a concrete route. If
19
+ # we rely only on the `Rails.application.routes.router`, then the
20
+ # recognize call would return the root route, neglecting PATH_INFO
21
+ # completely. For example:
22
+ # * a request is made to `marketing#pricing`
23
+ # * `Rails.application` recognizes it as `marketing#/` (incorrect)
24
+ # * `Marketing::Engine` recognizes it as `marketing#/pricing` (correct)
25
+ engines.each do |engine|
26
+ engine.routes.router.recognize(request_copy) do |route, _params|
27
+ path =
28
+ if engine == ::Rails.application
29
+ route.path.spec.to_s
30
+ else
31
+ "#{engine.engine_name}##{route.path.spec}"
32
+ end
33
+
34
+ # Rails can recognize multiple routes for the given request. For
35
+ # example, if we visit /users/2/edit, then Rails sees these routes:
36
+ # * "/users/:id/edit(.:format)"
37
+ # * "/"
38
+ #
39
+ # We return the first route as, what it seems, the most optimal
40
+ # approach.
41
+ return Route.new(path)
42
+ end
32
43
  end
33
44
 
34
45
  nil
35
46
  end
47
+
48
+ def self.engines
49
+ @engines ||= [*::Rails::Engine.subclasses, ::Rails.application]
50
+ end
51
+ private_class_method :engines
36
52
  end
37
53
  end
38
54
  end
@@ -43,10 +43,6 @@ module Airbrake
43
43
  @event.time
44
44
  end
45
45
 
46
- def end
47
- @event.end
48
- end
49
-
50
46
  def groups
51
47
  groups = {}
52
48
  groups[:db] = db_runtime if db_runtime > 0
@@ -59,7 +55,7 @@ module Airbrake
59
55
 
60
56
  if @event.payload[:exception]
61
57
  status = ActionDispatch::ExceptionWrapper.status_code_for_exception(
62
- @event.payload[:exception].first
58
+ @event.payload[:exception].first,
63
59
  )
64
60
  status = 500 if status == 0
65
61
 
@@ -16,20 +16,20 @@ module Airbrake
16
16
  # exist in Rails 5 anymore.
17
17
  app.config.middleware.insert_after(
18
18
  ActionDispatch::DebugExceptions,
19
- Airbrake::Rack::Middleware
19
+ Airbrake::Rack::Middleware,
20
20
  )
21
21
  elsif defined?(::ActiveRecord::ConnectionAdapters::ConnectionManagement)
22
22
  # Insert after ConnectionManagement to avoid DB connection leakage:
23
23
  # https://github.com/airbrake/airbrake/pull/568
24
24
  app.config.middleware.insert_after(
25
25
  ::ActiveRecord::ConnectionAdapters::ConnectionManagement,
26
- 'Airbrake::Rack::Middleware'
26
+ 'Airbrake::Rack::Middleware',
27
27
  )
28
28
  else
29
29
  # Insert after DebugExceptions for apps without ActiveRecord.
30
30
  app.config.middleware.insert_after(
31
31
  ActionDispatch::DebugExceptions,
32
- 'Airbrake::Rack::Middleware'
32
+ 'Airbrake::Rack::Middleware',
33
33
  )
34
34
  end
35
35
  end
@@ -55,21 +55,21 @@ module Airbrake
55
55
  require 'airbrake/rails/action_controller_route_subscriber'
56
56
  ActiveSupport::Notifications.subscribe(
57
57
  'start_processing.action_controller',
58
- Airbrake::Rails::ActionControllerRouteSubscriber.new
58
+ Airbrake::Rails::ActionControllerRouteSubscriber.new,
59
59
  )
60
60
 
61
61
  # Send route stats.
62
62
  require 'airbrake/rails/action_controller_notify_subscriber'
63
63
  ActiveSupport::Notifications.subscribe(
64
64
  'process_action.action_controller',
65
- Airbrake::Rails::ActionControllerNotifySubscriber.new
65
+ Airbrake::Rails::ActionControllerNotifySubscriber.new,
66
66
  )
67
67
 
68
68
  # Send performance breakdown: where a request spends its time.
69
69
  require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
70
70
  ActiveSupport::Notifications.subscribe(
71
71
  'process_action.action_controller',
72
- Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new
72
+ Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber.new,
73
73
  )
74
74
 
75
75
  require 'airbrake/rails/net_http' if defined?(Net) && defined?(Net::HTTP)
@@ -112,8 +112,8 @@ module Airbrake
112
112
  # Filter out parameters from SQL body.
113
113
  Airbrake.add_performance_filter(
114
114
  Airbrake::Filters::SqlFilter.new(
115
- ::ActiveRecord::Base.connection_config[:adapter]
116
- )
115
+ ::ActiveRecord::Base.connection_config[:adapter],
116
+ ),
117
117
  )
118
118
  end
119
119
  end
@@ -30,7 +30,7 @@ module Rake
30
30
  notice[:params].merge!(
31
31
  rake_task: task_info,
32
32
  execute_args: args,
33
- argv: ARGV.join(' ')
33
+ argv: ARGV.join(' '),
34
34
  )
35
35
 
36
36
  Airbrake.notify_sync(notice)
@@ -55,7 +55,7 @@ namespace :airbrake do
55
55
  username: ENV['USERNAME'],
56
56
  revision: ENV['REVISION'],
57
57
  repository: ENV['REPOSITORY'],
58
- version: ENV['VERSION']
58
+ version: ENV['VERSION'],
59
59
  }
60
60
  promise = Airbrake.notify_deploy(deploy_params)
61
61
  promise.then do
@@ -27,3 +27,33 @@ module Resque
27
27
  end
28
28
  end
29
29
  end
30
+
31
+ module Resque
32
+ # Measures elapsed time of a job and notifies Airbrake of the execution
33
+ # status.
34
+ #
35
+ # @since v9.6.0
36
+ class Job
37
+ # Store the original method to use it later.
38
+ alias perform_without_airbrake perform
39
+
40
+ def perform
41
+ timing = Airbrake::Benchmark.measure do
42
+ perform_without_airbrake
43
+ end
44
+ rescue StandardError => exception
45
+ Airbrake.notify_queue_sync(
46
+ queue: payload['class'],
47
+ error_count: 1,
48
+ timing: 0.01,
49
+ )
50
+ raise exception
51
+ else
52
+ Airbrake.notify_queue_sync(
53
+ queue: payload['class'],
54
+ error_count: 0,
55
+ timing: timing,
56
+ )
57
+ end
58
+ end
59
+ end
@@ -4,11 +4,23 @@ module Airbrake
4
4
  class ErrorHandler
5
5
  # rubocop:disable Lint/RescueException
6
6
  def call(worker, queue, _sqs_msg, body)
7
- yield
7
+ timing = Airbrake::Benchmark.measure do
8
+ yield
9
+ end
8
10
  rescue Exception => exception
9
11
  notify_airbrake(exception, worker, queue, body)
10
-
12
+ Airbrake.notify_queue(
13
+ queue: worker.class.to_s,
14
+ error_count: 1,
15
+ timing: 0.01,
16
+ )
11
17
  raise exception
18
+ else
19
+ Airbrake.notify_queue(
20
+ queue: worker.class.to_s,
21
+ error_count: 0,
22
+ timing: timing,
23
+ )
12
24
  end
13
25
  # rubocop:enable Lint/RescueException
14
26
 
@@ -24,7 +36,7 @@ module Airbrake
24
36
  def notice_context(queue, body)
25
37
  {
26
38
  queue: queue,
27
- body: body.is_a?(Array) ? { batch: body } : { body: body }
39
+ body: body.is_a?(Array) ? { batch: body } : { body: body },
28
40
  }
29
41
  end
30
42
  end
@@ -4,14 +4,25 @@ module Airbrake
4
4
  module Sidekiq
5
5
  # Provides integration with Sidekiq v2+.
6
6
  class ErrorHandler
7
- # rubocop:disable Lint/RescueException
8
7
  def call(_worker, context, _queue)
9
- yield
10
- rescue Exception => exception
8
+ timing = Airbrake::Benchmark.measure do
9
+ yield
10
+ end
11
+ rescue Exception => exception # rubocop:disable Lint/RescueException
11
12
  notify_airbrake(exception, context)
13
+ Airbrake.notify_queue(
14
+ queue: context['class'],
15
+ error_count: 1,
16
+ timing: 0.01,
17
+ )
12
18
  raise exception
19
+ else
20
+ Airbrake.notify_queue(
21
+ queue: context['class'],
22
+ error_count: 0,
23
+ timing: timing,
24
+ )
13
25
  end
14
- # rubocop:enable Lint/RescueException
15
26
 
16
27
  private
17
28
 
@@ -34,14 +45,8 @@ module Airbrake
34
45
  end
35
46
  end
36
47
 
37
- if Sidekiq::VERSION < '3'
38
- Sidekiq.configure_server do |config|
39
- config.server_middleware do |chain|
40
- chain.add(Airbrake::Sidekiq::ErrorHandler)
41
- end
42
- end
43
- else
44
- Sidekiq.configure_server do |config|
45
- config.error_handlers << Airbrake::Sidekiq::ErrorHandler.new.method(:notify_airbrake)
48
+ Sidekiq.configure_server do |config|
49
+ config.server_middleware do |chain|
50
+ chain.add(Airbrake::Sidekiq::ErrorHandler)
46
51
  end
47
52
  end
@@ -32,3 +32,35 @@ module Airbrake
32
32
  end
33
33
 
34
34
  Sneakers.error_reporters << Airbrake::Sneakers::ErrorReporter.new
35
+
36
+ module Sneakers
37
+ # @todo Migrate to Sneakers v2.12.0 middleware API when it's released
38
+ # @see https://github.com/jondot/sneakers/pull/364
39
+ module Worker
40
+ # Sneakers v2.7.0+ renamed `do_work` to `process_work`.
41
+ if method_defined?(:process_work)
42
+ alias process_work_without_airbrake process_work
43
+ else
44
+ alias process_work_without_airbrake do_work
45
+ end
46
+
47
+ def process_work(delivery_info, metadata, msg, handler)
48
+ timing = Airbrake::Benchmark.measure do
49
+ process_work_without_airbrake(delivery_info, metadata, msg, handler)
50
+ end
51
+ rescue Exception => exception # rubocop:disable Lint/RescueException
52
+ Airbrake.notify_queue(
53
+ queue: self.class.to_s,
54
+ error_count: 1,
55
+ timing: 0.01,
56
+ )
57
+ raise exception
58
+ else
59
+ Airbrake.notify_queue(
60
+ queue: self.class.to_s,
61
+ error_count: 0,
62
+ timing: timing,
63
+ )
64
+ end
65
+ end
66
+ end
@@ -1,5 +1,5 @@
1
1
  # We use Semantic Versioning v2.0.0
2
2
  # More information: http://semver.org/
3
3
  module Airbrake
4
- AIRBRAKE_VERSION = '9.5.5'.freeze
4
+ AIRBRAKE_VERSION = '10.0.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.5.5
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-02 00:00:00.000000000 Z
11
+ date: 2020-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: airbrake-ruby
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.8'
19
+ version: '4.12'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.8'
26
+ version: '4.12'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -254,6 +254,20 @@ dependencies:
254
254
  - - '='
255
255
  - !ruby/object:Gem::Version
256
256
  version: 1.9.0
257
+ - !ruby/object:Gem::Dependency
258
+ name: redis-namespace
259
+ requirement: !ruby/object:Gem::Requirement
260
+ requirements:
261
+ - - '='
262
+ - !ruby/object:Gem::Version
263
+ version: 1.6.0
264
+ type: :development
265
+ prerelease: false
266
+ version_requirements: !ruby/object:Gem::Requirement
267
+ requirements:
268
+ - - '='
269
+ - !ruby/object:Gem::Version
270
+ version: 1.6.0
257
271
  - !ruby/object:Gem::Dependency
258
272
  name: sidekiq
259
273
  requirement: !ruby/object:Gem::Requirement