airbrake-ruby 6.1.0 → 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby/async_sender.rb +11 -15
- data/lib/airbrake-ruby/backlog.rb +123 -0
- data/lib/airbrake-ruby/config.rb +7 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
- data/lib/airbrake-ruby/nested_exception.rb +22 -1
- data/lib/airbrake-ruby/notice.rb +5 -3
- data/lib/airbrake-ruby/notice_notifier.rb +1 -0
- data/lib/airbrake-ruby/performance_notifier.rb +1 -0
- data/lib/airbrake-ruby/response.rb +56 -5
- data/lib/airbrake-ruby/sync_sender.rb +41 -10
- data/lib/airbrake-ruby/version.rb +1 -1
- data/lib/airbrake-ruby.rb +2 -1
- metadata +5 -122
- data/spec/airbrake_spec.rb +0 -522
- data/spec/async_sender_spec.rb +0 -65
- data/spec/backtrace_spec.rb +0 -430
- data/spec/benchmark_spec.rb +0 -35
- data/spec/code_hunk_spec.rb +0 -124
- data/spec/config/processor_spec.rb +0 -167
- data/spec/config/validator_spec.rb +0 -204
- data/spec/config_spec.rb +0 -188
- data/spec/context_spec.rb +0 -54
- data/spec/deploy_notifier_spec.rb +0 -50
- data/spec/file_cache_spec.rb +0 -35
- data/spec/filter_chain_spec.rb +0 -124
- data/spec/filters/context_filter_spec.rb +0 -32
- data/spec/filters/dependency_filter_spec.rb +0 -14
- data/spec/filters/exception_attributes_filter_spec.rb +0 -52
- data/spec/filters/gem_root_filter_spec.rb +0 -44
- data/spec/filters/git_last_checkout_filter_spec.rb +0 -61
- data/spec/filters/git_repository_filter_spec.rb +0 -72
- data/spec/filters/git_revision_filter_spec.rb +0 -126
- data/spec/filters/keys_allowlist_spec.rb +0 -204
- data/spec/filters/keys_blocklist_spec.rb +0 -242
- data/spec/filters/root_directory_filter_spec.rb +0 -39
- data/spec/filters/sql_filter_spec.rb +0 -274
- data/spec/filters/system_exit_filter_spec.rb +0 -16
- data/spec/filters/thread_filter_spec.rb +0 -281
- data/spec/fixtures/notroot.txt +0 -7
- data/spec/fixtures/project_root/code.rb +0 -221
- data/spec/fixtures/project_root/empty_file.rb +0 -0
- data/spec/fixtures/project_root/long_line.txt +0 -1
- data/spec/fixtures/project_root/short_file.rb +0 -3
- data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +0 -5
- data/spec/helpers.rb +0 -9
- data/spec/ignorable_spec.rb +0 -14
- data/spec/inspectable_spec.rb +0 -45
- data/spec/loggable_spec.rb +0 -17
- data/spec/monotonic_time_spec.rb +0 -25
- data/spec/nested_exception_spec.rb +0 -73
- data/spec/notice_notifier/options_spec.rb +0 -269
- data/spec/notice_notifier_spec.rb +0 -361
- data/spec/notice_spec.rb +0 -300
- data/spec/performance_breakdown_spec.rb +0 -11
- data/spec/performance_notifier_spec.rb +0 -645
- data/spec/promise_spec.rb +0 -203
- data/spec/query_spec.rb +0 -11
- data/spec/queue_spec.rb +0 -18
- data/spec/remote_settings/callback_spec.rb +0 -162
- data/spec/remote_settings/settings_data_spec.rb +0 -348
- data/spec/remote_settings_spec.rb +0 -201
- data/spec/request_spec.rb +0 -9
- data/spec/response_spec.rb +0 -110
- data/spec/spec_helper.rb +0 -100
- data/spec/stashable_spec.rb +0 -23
- data/spec/stat_spec.rb +0 -39
- data/spec/sync_sender_spec.rb +0 -168
- data/spec/tdigest_spec.rb +0 -235
- data/spec/thread_pool_spec.rb +0 -196
- data/spec/time_truncate_spec.rb +0 -30
- data/spec/timed_trace_spec.rb +0 -127
- data/spec/truncator_spec.rb +0 -267
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 957248cf16866b1a8c873216c0179a79cc39189758f364254ae6534cde41ebda
|
4
|
+
data.tar.gz: d579021d4b619b7307643559ca1a0d19f22782305b3a91a56c25d6e393402949
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 367780539773c946676d19ef6e76ed4b98abf8009f4d3c8715837b07dafaaa1bee207bc01fac0b04765bf7889a22d0ca3802462e3d0c062cc708fb9b016b103b
|
7
|
+
data.tar.gz: 1deb29c06f902730deb860150354da8c8a781cf5082daeb5305c47b33d6c6221d5d35fdc6ad2311d4dff22923cc0b015e6e7ceac756365709dc69987e90d7326
|
@@ -5,20 +5,18 @@ module Airbrake
|
|
5
5
|
# @api private
|
6
6
|
# @since v1.0.0
|
7
7
|
class AsyncSender
|
8
|
-
include Loggable
|
9
|
-
|
10
8
|
def initialize(method = :post, name = 'async-sender')
|
11
9
|
@config = Airbrake::Config.instance
|
12
|
-
@
|
10
|
+
@sync_sender = SyncSender.new(method)
|
13
11
|
@name = name
|
14
12
|
end
|
15
13
|
|
16
14
|
# Asynchronously sends a notice to Airbrake.
|
17
15
|
#
|
18
|
-
# @param [
|
16
|
+
# @param [Airbrake::Notice] payload Whatever needs to be sent
|
19
17
|
# @return [Airbrake::Promise]
|
20
|
-
def send(
|
21
|
-
unless thread_pool << [
|
18
|
+
def send(notice, promise, endpoint = @config.error_endpoint)
|
19
|
+
unless thread_pool << [notice, promise, endpoint]
|
22
20
|
return promise.reject(
|
23
21
|
"AsyncSender has reached its capacity of #{@config.queue_size}",
|
24
22
|
)
|
@@ -29,6 +27,7 @@ module Airbrake
|
|
29
27
|
|
30
28
|
# @return [void]
|
31
29
|
def close
|
30
|
+
@sync_sender.close
|
32
31
|
thread_pool.close
|
33
32
|
end
|
34
33
|
|
@@ -45,15 +44,12 @@ module Airbrake
|
|
45
44
|
private
|
46
45
|
|
47
46
|
def thread_pool
|
48
|
-
@thread_pool ||=
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
block: proc { |args| sender.send(*args) },
|
55
|
-
)
|
56
|
-
end
|
47
|
+
@thread_pool ||= ThreadPool.new(
|
48
|
+
name: @name,
|
49
|
+
worker_size: @config.workers,
|
50
|
+
queue_size: @config.queue_size,
|
51
|
+
block: proc { |args| @sync_sender.send(*args) },
|
52
|
+
)
|
57
53
|
end
|
58
54
|
end
|
59
55
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Airbrake
|
2
|
+
# Backlog accepts notices and APM events and synchronously sends them in the
|
3
|
+
# background at regular intervals. The backlog is a queue of data that failed
|
4
|
+
# to be sent due to some error. In a nutshell, it's a retry mechanism.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since v6.2.0
|
8
|
+
class Backlog
|
9
|
+
include Loggable
|
10
|
+
|
11
|
+
# @return [Integer] how many records to keep in the backlog
|
12
|
+
BACKLOG_SIZE = 100
|
13
|
+
|
14
|
+
# @return [Integer] flush period in seconds
|
15
|
+
TWO_MINUTES = 60 * 2
|
16
|
+
|
17
|
+
def initialize(sync_sender, flush_period = TWO_MINUTES)
|
18
|
+
@sync_sender = sync_sender
|
19
|
+
@flush_period = flush_period
|
20
|
+
@queue = SizedQueue.new(BACKLOG_SIZE).extend(MonitorMixin)
|
21
|
+
@has_backlog_data = @queue.new_cond
|
22
|
+
@schedule_flush = nil
|
23
|
+
|
24
|
+
@seen = Set.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Appends data to the backlog. Once appended, the flush schedule will
|
28
|
+
# start. Chainable.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# backlog << [{ 'data' => 1 }, 'https://airbrake.io/api']
|
32
|
+
#
|
33
|
+
# @param [Array<#to_json, String>] data An array of two elements, where the
|
34
|
+
# first element is the data we are sending and the second element is the
|
35
|
+
# URL that we are sending to
|
36
|
+
# @return [self]
|
37
|
+
def <<(data)
|
38
|
+
@queue.synchronize do
|
39
|
+
return self if @seen.include?(data)
|
40
|
+
|
41
|
+
@seen << data
|
42
|
+
|
43
|
+
begin
|
44
|
+
@queue.push(data, true)
|
45
|
+
rescue ThreadError
|
46
|
+
logger.error("#{LOG_LABEL} Airbrake::Backlog full")
|
47
|
+
return self
|
48
|
+
end
|
49
|
+
|
50
|
+
@has_backlog_data.signal
|
51
|
+
schedule_flush
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Closes all the resources that this sender has allocated.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
# @since v6.2.0
|
61
|
+
def close
|
62
|
+
@queue.synchronize do
|
63
|
+
if @schedule_flush
|
64
|
+
@schedule_flush.kill
|
65
|
+
logger.debug("#{LOG_LABEL} Airbrake::Backlog closed")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def schedule_flush
|
73
|
+
@schedule_flush ||= Thread.new do
|
74
|
+
loop do
|
75
|
+
@queue.synchronize do
|
76
|
+
wait
|
77
|
+
next if @queue.empty?
|
78
|
+
|
79
|
+
flush
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def wait
|
86
|
+
@has_backlog_data.wait(@flush_period) while time_elapsed < @flush_period
|
87
|
+
@last_flush = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def time_elapsed
|
91
|
+
MonotonicTime.time_in_s - last_flush
|
92
|
+
end
|
93
|
+
|
94
|
+
def last_flush
|
95
|
+
@last_flush ||= MonotonicTime.time_in_s
|
96
|
+
end
|
97
|
+
|
98
|
+
def flush
|
99
|
+
unless @queue.empty?
|
100
|
+
logger.debug(
|
101
|
+
"#{LOG_LABEL} Airbrake::Backlog flushing #{@queue.size} messages",
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
failed = 0
|
106
|
+
|
107
|
+
until @queue.empty?
|
108
|
+
data, endpoint = @queue.pop
|
109
|
+
promise = Airbrake::Promise.new
|
110
|
+
@sync_sender.send(data, promise, endpoint)
|
111
|
+
failed += 1 if promise.rejected?
|
112
|
+
end
|
113
|
+
|
114
|
+
if failed > 0
|
115
|
+
logger.debug(
|
116
|
+
"#{LOG_LABEL} Airbrake::Backlog #{failed} messages were not flushed",
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
@seen.clear
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -136,6 +136,12 @@ module Airbrake
|
|
136
136
|
# @since v5.2.0
|
137
137
|
attr_accessor :remote_config
|
138
138
|
|
139
|
+
# @return [Boolean] true if the library should keep a backlog of failed
|
140
|
+
# notices or APM events and retry them after an interval, false otherwise
|
141
|
+
# @api public
|
142
|
+
# @since v6.2.0
|
143
|
+
attr_accessor :backlog
|
144
|
+
|
139
145
|
class << self
|
140
146
|
# @return [Config]
|
141
147
|
attr_writer :instance
|
@@ -180,6 +186,7 @@ module Airbrake
|
|
180
186
|
self.job_stats = true
|
181
187
|
self.error_notifications = true
|
182
188
|
self.remote_config = true
|
189
|
+
self.backlog = true
|
183
190
|
|
184
191
|
merge(user_config)
|
185
192
|
end
|
@@ -9,6 +9,18 @@ module Airbrake
|
|
9
9
|
# can unwrap. Exceptions that have a longer cause chain will be ignored
|
10
10
|
MAX_NESTED_EXCEPTIONS = 3
|
11
11
|
|
12
|
+
# On Ruby 3.1+, the error highlighting gem can produce messages that can
|
13
|
+
# span multiple lines. We don't display multiline error messages in the
|
14
|
+
# title of the notice in the Airbrake dashboard. Therefore, we want to strip
|
15
|
+
# out the higlighting part so that the errors look consistent. The full
|
16
|
+
# message with the exception will be attached to the notice body.
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
RUBY_31_ERROR_HIGHLIGHTING_DIVIDER = "\n\n".freeze
|
20
|
+
|
21
|
+
# @return [Hash] the options for +String#encode+
|
22
|
+
ENCODING_OPTIONS = { invalid: :replace, undef: :replace }.freeze
|
23
|
+
|
12
24
|
def initialize(exception)
|
13
25
|
@exception = exception
|
14
26
|
end
|
@@ -16,7 +28,7 @@ module Airbrake
|
|
16
28
|
def as_json
|
17
29
|
unwind_exceptions.map do |exception|
|
18
30
|
{ type: exception.class.name,
|
19
|
-
message: exception
|
31
|
+
message: message(exception),
|
20
32
|
backtrace: Backtrace.parse(exception) }
|
21
33
|
end
|
22
34
|
end
|
@@ -34,5 +46,14 @@ module Airbrake
|
|
34
46
|
|
35
47
|
exception_list
|
36
48
|
end
|
49
|
+
|
50
|
+
def message(exception)
|
51
|
+
return unless (msg = exception.message)
|
52
|
+
|
53
|
+
msg
|
54
|
+
.encode(Encoding::UTF_8, **ENCODING_OPTIONS)
|
55
|
+
.split(RUBY_31_ERROR_HIGHLIGHTING_DIVIDER)
|
56
|
+
.first
|
57
|
+
end
|
37
58
|
end
|
38
59
|
end
|
data/lib/airbrake-ruby/notice.rb
CHANGED
@@ -49,16 +49,17 @@ module Airbrake
|
|
49
49
|
# @api private
|
50
50
|
def initialize(exception, params = {})
|
51
51
|
@config = Airbrake::Config.instance
|
52
|
+
@truncator = Airbrake::Truncator.new(PAYLOAD_MAX_SIZE)
|
53
|
+
|
52
54
|
@payload = {
|
53
55
|
errors: NestedException.new(exception).as_json,
|
54
|
-
context: context,
|
56
|
+
context: context(exception),
|
55
57
|
environment: {
|
56
58
|
program_name: $PROGRAM_NAME,
|
57
59
|
},
|
58
60
|
session: {},
|
59
61
|
params: params,
|
60
62
|
}
|
61
|
-
@truncator = Airbrake::Truncator.new(PAYLOAD_MAX_SIZE)
|
62
63
|
|
63
64
|
stash[:exception] = exception
|
64
65
|
end
|
@@ -118,7 +119,7 @@ module Airbrake
|
|
118
119
|
|
119
120
|
private
|
120
121
|
|
121
|
-
def context
|
122
|
+
def context(exception)
|
122
123
|
{
|
123
124
|
version: @config.app_version,
|
124
125
|
versions: @config.versions,
|
@@ -132,6 +133,7 @@ module Airbrake
|
|
132
133
|
hostname: HOSTNAME,
|
133
134
|
|
134
135
|
severity: DEFAULT_SEVERITY,
|
136
|
+
error_message: @truncator.truncate(exception.message),
|
135
137
|
}.merge(CONTEXT).delete_if { |_key, val| val.nil? || val.empty? }
|
136
138
|
end
|
137
139
|
|
@@ -8,9 +8,56 @@ module Airbrake
|
|
8
8
|
# @return [Integer] the limit of the response body
|
9
9
|
TRUNCATE_LIMIT = 100
|
10
10
|
|
11
|
+
# @return [Integer] HTTP code returned when the server cannot or will not
|
12
|
+
# process the request due to something that is perceived to be a client
|
13
|
+
# error
|
14
|
+
# @since v6.2.0
|
15
|
+
BAD_REQUEST = 400
|
16
|
+
|
17
|
+
# @return [Integer] HTTP code returned when client request has not been
|
18
|
+
# completed because it lacks valid authentication credentials for the
|
19
|
+
# requested resource
|
20
|
+
# @since v6.2.0
|
21
|
+
UNAUTHORIZED = 401
|
22
|
+
|
23
|
+
# @return [Integer] HTTP code returned when the server understands the
|
24
|
+
# request but refuses to authorize it
|
25
|
+
# @since v6.2.0
|
26
|
+
FORBIDDEN = 403
|
27
|
+
|
28
|
+
# @return [Integer] HTTP code returned when the server would like to shut
|
29
|
+
# down this unused connection
|
30
|
+
# @since v6.2.0
|
31
|
+
REQUEST_TIMEOUT = 408
|
32
|
+
|
33
|
+
# @return [Integer] HTTP code returned when there's a request conflict with
|
34
|
+
# the current state of the target resource
|
35
|
+
# @since v6.2.0
|
36
|
+
CONFLICT = 409
|
37
|
+
|
38
|
+
# @return [Integer]
|
39
|
+
# @since v6.2.0
|
40
|
+
ENHANCE_YOUR_CALM = 420
|
41
|
+
|
11
42
|
# @return [Integer] HTTP code returned when an IP sends over 10k/min notices
|
12
43
|
TOO_MANY_REQUESTS = 429
|
13
44
|
|
45
|
+
# @return [Integer] HTTP code returned when the server encountered an
|
46
|
+
# unexpected condition that prevented it from fulfilling the request
|
47
|
+
# @since v6.2.0
|
48
|
+
INTERNAL_SERVER_ERROR = 500
|
49
|
+
|
50
|
+
# @return [Integer] HTTP code returened when the server, while acting as a
|
51
|
+
# gateway or proxy, received an invalid response from the upstream server
|
52
|
+
# @since v6.2.0
|
53
|
+
BAD_GATEWAY = 502
|
54
|
+
|
55
|
+
# @return [Integer] HTTP code returened when the server, while acting as a
|
56
|
+
# gateway or proxy, did not get a response in time from the upstream
|
57
|
+
# server that it needed in order to complete the request
|
58
|
+
# @since v6.2.0
|
59
|
+
GATEWAY_TIMEOUT = 504
|
60
|
+
|
14
61
|
class << self
|
15
62
|
include Loggable
|
16
63
|
end
|
@@ -33,24 +80,28 @@ module Airbrake
|
|
33
80
|
parsed_body = JSON.parse(body)
|
34
81
|
logger.debug("#{LOG_LABEL} #{name} (#{code}): #{parsed_body}")
|
35
82
|
parsed_body
|
36
|
-
when
|
83
|
+
when BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, ENHANCE_YOUR_CALM
|
37
84
|
parsed_body = JSON.parse(body)
|
38
85
|
logger.error("#{LOG_LABEL} #{parsed_body['message']}")
|
39
|
-
parsed_body
|
86
|
+
parsed_body.merge('code' => code, 'error' => parsed_body['message'])
|
40
87
|
when TOO_MANY_REQUESTS
|
41
88
|
parsed_body = JSON.parse(body)
|
42
89
|
msg = "#{LOG_LABEL} #{parsed_body['message']}"
|
43
90
|
logger.error(msg)
|
44
|
-
{
|
91
|
+
{
|
92
|
+
'code' => code,
|
93
|
+
'error' => msg,
|
94
|
+
'rate_limit_reset' => rate_limit_reset(response),
|
95
|
+
}
|
45
96
|
else
|
46
97
|
body_msg = truncated_body(body)
|
47
98
|
logger.error("#{LOG_LABEL} unexpected code (#{code}). Body: #{body_msg}")
|
48
|
-
{ 'error' => body_msg }
|
99
|
+
{ 'code' => code, 'error' => body_msg }
|
49
100
|
end
|
50
101
|
rescue StandardError => ex
|
51
102
|
body_msg = truncated_body(body)
|
52
103
|
logger.error("#{LOG_LABEL} error while parsing body (#{ex}). Body: #{body_msg}")
|
53
|
-
{ 'error' => ex.inspect }
|
104
|
+
{ 'code' => code, 'error' => ex.inspect }
|
54
105
|
end
|
55
106
|
end
|
56
107
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
@@ -9,6 +9,20 @@ module Airbrake
|
|
9
9
|
# @return [String] body for HTTP requests
|
10
10
|
CONTENT_TYPE = 'application/json'.freeze
|
11
11
|
|
12
|
+
# @return [Array<Integer>] response codes that are good to be backlogged
|
13
|
+
# @since v6.2.0
|
14
|
+
BACKLOGGABLE_STATUS_CODES = [
|
15
|
+
Response::BAD_REQUEST,
|
16
|
+
Response::FORBIDDEN,
|
17
|
+
Response::ENHANCE_YOUR_CALM,
|
18
|
+
Response::REQUEST_TIMEOUT,
|
19
|
+
Response::CONFLICT,
|
20
|
+
Response::TOO_MANY_REQUESTS,
|
21
|
+
Response::INTERNAL_SERVER_ERROR,
|
22
|
+
Response::BAD_GATEWAY,
|
23
|
+
Response::GATEWAY_TIMEOUT,
|
24
|
+
].freeze
|
25
|
+
|
12
26
|
include Loggable
|
13
27
|
|
14
28
|
# @param [Symbol] method HTTP method to use to send payload
|
@@ -16,6 +30,7 @@ module Airbrake
|
|
16
30
|
@config = Airbrake::Config.instance
|
17
31
|
@method = method
|
18
32
|
@rate_limit_reset = Time.now
|
33
|
+
@backlog = Backlog.new(self) if @config.backlog
|
19
34
|
end
|
20
35
|
|
21
36
|
# Sends a POST or PUT request to the given +endpoint+ with the +data+ payload.
|
@@ -26,15 +41,11 @@ module Airbrake
|
|
26
41
|
def send(data, promise, endpoint = @config.error_endpoint)
|
27
42
|
return promise if rate_limited_ip?(promise)
|
28
43
|
|
29
|
-
response = nil
|
30
44
|
req = build_request(endpoint, data)
|
31
|
-
|
32
45
|
return promise if missing_body?(req, promise)
|
33
46
|
|
34
|
-
https = build_https(endpoint)
|
35
|
-
|
36
47
|
begin
|
37
|
-
response =
|
48
|
+
response = build_https(endpoint).request(req)
|
38
49
|
rescue StandardError => ex
|
39
50
|
reason = "#{LOG_LABEL} HTTP error: #{ex}"
|
40
51
|
logger.error(reason)
|
@@ -42,15 +53,22 @@ module Airbrake
|
|
42
53
|
end
|
43
54
|
|
44
55
|
parsed_resp = Response.parse(response)
|
45
|
-
|
46
|
-
|
47
|
-
end
|
56
|
+
handle_rate_limit(parsed_resp)
|
57
|
+
@backlog << [data, endpoint] if add_to_backlog?(parsed_resp)
|
48
58
|
|
49
59
|
return promise.reject(parsed_resp['error']) if parsed_resp.key?('error')
|
50
60
|
|
51
61
|
promise.resolve(parsed_resp)
|
52
62
|
end
|
53
63
|
|
64
|
+
# Closes all the resources that this sender has allocated.
|
65
|
+
#
|
66
|
+
# @return [void]
|
67
|
+
# @since v6.2.0
|
68
|
+
def close
|
69
|
+
@backlog.close
|
70
|
+
end
|
71
|
+
|
54
72
|
private
|
55
73
|
|
56
74
|
def build_https(uri)
|
@@ -80,12 +98,25 @@ module Airbrake
|
|
80
98
|
req['Authorization'] = "Bearer #{@config.project_key}"
|
81
99
|
req['Content-Type'] = CONTENT_TYPE
|
82
100
|
req['User-Agent'] =
|
83
|
-
"#{Airbrake::NOTIFIER_INFO[:name]}/#{Airbrake::AIRBRAKE_RUBY_VERSION}" \
|
84
|
-
"
|
101
|
+
"#{Airbrake::NOTIFIER_INFO[:name]}/#{Airbrake::AIRBRAKE_RUBY_VERSION} " \
|
102
|
+
"Ruby/#{RUBY_VERSION}"
|
85
103
|
|
86
104
|
req
|
87
105
|
end
|
88
106
|
|
107
|
+
def handle_rate_limit(parsed_resp)
|
108
|
+
return unless parsed_resp.key?('rate_limit_reset')
|
109
|
+
|
110
|
+
@rate_limit_reset = parsed_resp['rate_limit_reset']
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_to_backlog?(parsed_resp)
|
114
|
+
return unless @backlog
|
115
|
+
return unless parsed_resp.key?('code')
|
116
|
+
|
117
|
+
BACKLOGGABLE_STATUS_CODES.include?(parsed_resp['code'])
|
118
|
+
end
|
119
|
+
|
89
120
|
def proxy_params
|
90
121
|
return unless @config.proxy.key?(:host)
|
91
122
|
|
data/lib/airbrake-ruby.rb
CHANGED
@@ -18,9 +18,9 @@ require 'airbrake-ruby/remote_settings/settings_data'
|
|
18
18
|
require 'airbrake-ruby/remote_settings'
|
19
19
|
require 'airbrake-ruby/promise'
|
20
20
|
require 'airbrake-ruby/thread_pool'
|
21
|
+
require 'airbrake-ruby/response'
|
21
22
|
require 'airbrake-ruby/sync_sender'
|
22
23
|
require 'airbrake-ruby/async_sender'
|
23
|
-
require 'airbrake-ruby/response'
|
24
24
|
require 'airbrake-ruby/nested_exception'
|
25
25
|
require 'airbrake-ruby/ignorable'
|
26
26
|
require 'airbrake-ruby/inspectable'
|
@@ -59,6 +59,7 @@ require 'airbrake-ruby/monotonic_time'
|
|
59
59
|
require 'airbrake-ruby/timed_trace'
|
60
60
|
require 'airbrake-ruby/queue'
|
61
61
|
require 'airbrake-ruby/context'
|
62
|
+
require 'airbrake-ruby/backlog'
|
62
63
|
|
63
64
|
# Airbrake is a thin wrapper around instances of the notifier classes (such as
|
64
65
|
# notice, performance & deploy notifiers). It creates a way to access them via a
|