airbrake-ruby 4.6.0 → 6.2.2
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.
- checksums.yaml +5 -5
- data/lib/airbrake-ruby/async_sender.rb +24 -109
- data/lib/airbrake-ruby/backlog.rb +123 -0
- data/lib/airbrake-ruby/backtrace.rb +8 -7
- data/lib/airbrake-ruby/benchmark.rb +1 -1
- data/lib/airbrake-ruby/code_hunk.rb +1 -1
- data/lib/airbrake-ruby/config/processor.rb +77 -0
- data/lib/airbrake-ruby/config/validator.rb +9 -3
- data/lib/airbrake-ruby/config.rb +78 -19
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
- data/lib/airbrake-ruby/file_cache.rb +6 -0
- data/lib/airbrake-ruby/filter_chain.rb +18 -1
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +3 -3
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +7 -7
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
- data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
- data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
- data/lib/airbrake-ruby/filters/keys_filter.rb +41 -22
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +35 -11
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +6 -5
- data/lib/airbrake-ruby/grouppable.rb +12 -0
- data/lib/airbrake-ruby/ignorable.rb +1 -2
- data/lib/airbrake-ruby/inspectable.rb +2 -2
- data/lib/airbrake-ruby/loggable.rb +1 -1
- data/lib/airbrake-ruby/mergeable.rb +12 -0
- data/lib/airbrake-ruby/monotonic_time.rb +6 -1
- data/lib/airbrake-ruby/nested_exception.rb +22 -1
- data/lib/airbrake-ruby/notice.rb +12 -17
- data/lib/airbrake-ruby/notice_notifier.rb +15 -7
- data/lib/airbrake-ruby/performance_breakdown.rb +16 -9
- data/lib/airbrake-ruby/performance_notifier.rb +106 -54
- data/lib/airbrake-ruby/promise.rb +1 -0
- data/lib/airbrake-ruby/query.rb +20 -14
- data/lib/airbrake-ruby/queue.rb +65 -0
- data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
- data/lib/airbrake-ruby/remote_settings.rb +128 -0
- data/lib/airbrake-ruby/request.rb +14 -11
- data/lib/airbrake-ruby/response.rb +56 -5
- data/lib/airbrake-ruby/stat.rb +27 -34
- data/lib/airbrake-ruby/sync_sender.rb +43 -11
- data/lib/airbrake-ruby/tdigest.rb +52 -66
- data/lib/airbrake-ruby/thread_pool.rb +139 -0
- data/lib/airbrake-ruby/time_truncate.rb +2 -2
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/truncator.rb +10 -4
- data/lib/airbrake-ruby/version.rb +11 -1
- data/lib/airbrake-ruby.rb +157 -78
- metadata +122 -116
- data/spec/airbrake_spec.rb +0 -324
- data/spec/async_sender_spec.rb +0 -155
- data/spec/backtrace_spec.rb +0 -427
- data/spec/benchmark_spec.rb +0 -33
- data/spec/code_hunk_spec.rb +0 -115
- data/spec/config/validator_spec.rb +0 -184
- data/spec/config_spec.rb +0 -154
- data/spec/deploy_notifier_spec.rb +0 -48
- data/spec/file_cache.rb +0 -36
- data/spec/filter_chain_spec.rb +0 -92
- data/spec/filters/context_filter_spec.rb +0 -23
- data/spec/filters/dependency_filter_spec.rb +0 -12
- data/spec/filters/exception_attributes_filter_spec.rb +0 -50
- data/spec/filters/gem_root_filter_spec.rb +0 -41
- data/spec/filters/git_last_checkout_filter_spec.rb +0 -46
- data/spec/filters/git_repository_filter.rb +0 -61
- data/spec/filters/git_revision_filter_spec.rb +0 -126
- data/spec/filters/keys_blacklist_spec.rb +0 -225
- data/spec/filters/keys_whitelist_spec.rb +0 -194
- data/spec/filters/root_directory_filter_spec.rb +0 -39
- data/spec/filters/sql_filter_spec.rb +0 -219
- data/spec/filters/system_exit_filter_spec.rb +0 -14
- data/spec/filters/thread_filter_spec.rb +0 -277
- 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/monotonic_time_spec.rb +0 -12
- data/spec/nested_exception_spec.rb +0 -73
- data/spec/notice_notifier_spec/options_spec.rb +0 -259
- data/spec/notice_notifier_spec.rb +0 -356
- data/spec/notice_spec.rb +0 -296
- data/spec/performance_breakdown_spec.rb +0 -12
- data/spec/performance_notifier_spec.rb +0 -435
- data/spec/promise_spec.rb +0 -197
- data/spec/query_spec.rb +0 -11
- data/spec/request_spec.rb +0 -11
- data/spec/response_spec.rb +0 -88
- data/spec/spec_helper.rb +0 -100
- data/spec/stashable_spec.rb +0 -23
- data/spec/stat_spec.rb +0 -47
- data/spec/sync_sender_spec.rb +0 -133
- data/spec/tdigest_spec.rb +0 -230
- data/spec/time_truncate_spec.rb +0 -13
- data/spec/timed_trace_spec.rb +0 -125
- data/spec/truncator_spec.rb +0 -238
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::Filters::ThreadFilter do
|
|
2
|
-
let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
|
|
3
|
-
|
|
4
|
-
def new_thread
|
|
5
|
-
Thread.new do
|
|
6
|
-
th = Thread.current
|
|
7
|
-
|
|
8
|
-
# Ensure a thread always has some variable to make sure the
|
|
9
|
-
# :fiber_variables Hash is always present.
|
|
10
|
-
th[:random_var] = 42
|
|
11
|
-
yield(th)
|
|
12
|
-
end.join
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
describe "thread variables" do
|
|
16
|
-
shared_examples "expected thread variable" do |var|
|
|
17
|
-
it "attaches the thread variable" do
|
|
18
|
-
new_thread do |th|
|
|
19
|
-
th.thread_variable_set(:bingo, var)
|
|
20
|
-
subject.call(notice)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
expect(notice[:params][:thread][:thread_variables][:bingo]).to eq(var)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
context "given nil" do
|
|
28
|
-
include_examples "expected thread variable", nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
context "given true" do
|
|
32
|
-
include_examples "expected thread variable", true
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context "given false" do
|
|
36
|
-
include_examples "expected thread variable", false
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
context "given a String" do
|
|
40
|
-
include_examples "expected thread variable", 'bango'
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context "given a Symbol" do
|
|
44
|
-
include_examples "expected thread variable", :bango
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context "given a Regexp" do
|
|
48
|
-
include_examples "expected thread variable", /bango/
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
context "given an Integer" do
|
|
52
|
-
include_examples "expected thread variable", 1
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context "given a Float" do
|
|
56
|
-
include_examples "expected thread variable", 1.01
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
context "given an Object" do
|
|
60
|
-
it "converts it to a String and attaches" do
|
|
61
|
-
new_thread do |th|
|
|
62
|
-
th.thread_variable_set(:bingo, Object.new)
|
|
63
|
-
subject.call(notice)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
vars = notice[:params][:thread][:thread_variables]
|
|
67
|
-
expect(vars[:bingo]).to match(/\A#<Object:.+>\z/)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
context "given an Array of nested Hashes with complex objects" do
|
|
72
|
-
let(:var) do
|
|
73
|
-
[
|
|
74
|
-
{
|
|
75
|
-
bango: {
|
|
76
|
-
bongo: [
|
|
77
|
-
{
|
|
78
|
-
bish: {
|
|
79
|
-
bash: 'foo',
|
|
80
|
-
bosh: Object.new
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
123
|
|
87
|
-
]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it "converts objects to a safe objects" do
|
|
91
|
-
new_thread do |th|
|
|
92
|
-
th.thread_variable_set(:bingo, var)
|
|
93
|
-
subject.call(notice)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
vars = notice[:params][:thread][:thread_variables]
|
|
97
|
-
expect(vars[:bingo]).to(
|
|
98
|
-
match(
|
|
99
|
-
[
|
|
100
|
-
{
|
|
101
|
-
bango: {
|
|
102
|
-
bongo: [
|
|
103
|
-
{
|
|
104
|
-
bish: {
|
|
105
|
-
bash: 'foo',
|
|
106
|
-
bosh: /\A#<Object:.+>\z/
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
123
|
|
113
|
-
]
|
|
114
|
-
)
|
|
115
|
-
)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it "ignores thread variables starting with an underscore" do
|
|
120
|
-
var = :__recursive_key__
|
|
121
|
-
|
|
122
|
-
new_thread do |th|
|
|
123
|
-
th.thread_variable_set(var, :bingo)
|
|
124
|
-
subject.call(notice)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
thread_variables = notice[:params][:thread][:thread_variables]
|
|
128
|
-
expect(thread_variables).to be_nil
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
describe "fiber variables" do
|
|
133
|
-
shared_examples "expected fiber variable" do |var|
|
|
134
|
-
it "attaches the fiber variable" do
|
|
135
|
-
new_thread do |th|
|
|
136
|
-
th[:bingo] = var
|
|
137
|
-
subject.call(notice)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
expect(notice[:params][:thread][:fiber_variables][:bingo]).to eq(var)
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
context "given nil" do
|
|
145
|
-
include_examples "expected fiber variable", nil
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
context "given true" do
|
|
149
|
-
include_examples "expected fiber variable", true
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
context "given false" do
|
|
153
|
-
include_examples "expected fiber variable", false
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
context "given a String" do
|
|
157
|
-
include_examples "expected fiber variable", 'bango'
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
context "given a Symbol" do
|
|
161
|
-
include_examples "expected fiber variable", :bango
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
context "given a Regexp" do
|
|
165
|
-
include_examples "expected fiber variable", /bango/
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
context "given an Integer" do
|
|
169
|
-
include_examples "expected fiber variable", 1
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
context "given a Float" do
|
|
173
|
-
include_examples "expected fiber variable", 1.01
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
context "given an Object" do
|
|
177
|
-
it "converts it to a String and attaches" do
|
|
178
|
-
new_thread do |th|
|
|
179
|
-
th[:bingo] = Object.new
|
|
180
|
-
subject.call(notice)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
vars = notice[:params][:thread][:fiber_variables]
|
|
184
|
-
expect(vars[:bingo]).to match(/\A#<Object:.+>\z/)
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
context "given an Array of nested Hashes with complex objects" do
|
|
189
|
-
let(:var) do
|
|
190
|
-
[
|
|
191
|
-
{
|
|
192
|
-
bango: {
|
|
193
|
-
bongo: [
|
|
194
|
-
{
|
|
195
|
-
bish: {
|
|
196
|
-
bash: 'foo',
|
|
197
|
-
bosh: Object.new
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
]
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
123
|
|
204
|
-
]
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it "converts objects to a safe objects" do
|
|
208
|
-
new_thread do |th|
|
|
209
|
-
th[:bingo] = var
|
|
210
|
-
subject.call(notice)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
vars = notice[:params][:thread][:fiber_variables]
|
|
214
|
-
expect(vars[:bingo]).to(
|
|
215
|
-
match(
|
|
216
|
-
[
|
|
217
|
-
{
|
|
218
|
-
bango: {
|
|
219
|
-
bongo: [
|
|
220
|
-
{
|
|
221
|
-
bish: {
|
|
222
|
-
bash: 'foo',
|
|
223
|
-
bosh: /\A#<Object:.+>\z/
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
]
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
123
|
|
230
|
-
]
|
|
231
|
-
)
|
|
232
|
-
)
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it "appends name", skip: !Thread.current.respond_to?(:name) do
|
|
238
|
-
new_thread do |th|
|
|
239
|
-
th.name = 'bingo'
|
|
240
|
-
subject.call(notice)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
expect(notice[:params][:thread][:name]).to eq('bingo')
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
it "appends thread inspect (self)" do
|
|
247
|
-
subject.call(notice)
|
|
248
|
-
expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+ run>\z/)
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
it "appends thread group" do
|
|
252
|
-
subject.call(notice)
|
|
253
|
-
expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+ run>\z/)
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
it "appends priority" do
|
|
257
|
-
subject.call(notice)
|
|
258
|
-
expect(notice[:params][:thread][:priority]).to eq(0)
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
it "appends safe_level", skip: Airbrake::JRUBY do
|
|
262
|
-
subject.call(notice)
|
|
263
|
-
expect(notice[:params][:thread][:safe_level]).to eq(0)
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
it "ignores fiber variables starting with an underscore" do
|
|
267
|
-
key = :__recursive_key__
|
|
268
|
-
|
|
269
|
-
new_thread do |th|
|
|
270
|
-
th[key] = :bingo
|
|
271
|
-
subject.call(notice)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
fiber_variables = notice[:params][:thread][:fiber_variables]
|
|
275
|
-
expect(fiber_variables[key]).to be_nil
|
|
276
|
-
end
|
|
277
|
-
end
|
data/spec/fixtures/notroot.txt
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
module Airbrake
|
|
2
|
-
##
|
|
3
|
-
# Represents a chunk of information that is meant to be either sent to
|
|
4
|
-
# Airbrake or ignored completely.
|
|
5
|
-
#
|
|
6
|
-
# @since v1.0.0
|
|
7
|
-
class Notice
|
|
8
|
-
##
|
|
9
|
-
# @return [Hash{Symbol=>String}] the information about the notifier library
|
|
10
|
-
NOTIFIER = {
|
|
11
|
-
name: 'airbrake-ruby'.freeze,
|
|
12
|
-
version: Airbrake::AIRBRAKE_RUBY_VERSION,
|
|
13
|
-
url: 'https://github.com/airbrake/airbrake-ruby'.freeze
|
|
14
|
-
}.freeze
|
|
15
|
-
|
|
16
|
-
##
|
|
17
|
-
# @return [Hash{Symbol=>String,Hash}] the information to be displayed in the
|
|
18
|
-
# Context tab in the dashboard
|
|
19
|
-
CONTEXT = {
|
|
20
|
-
os: RUBY_PLATFORM,
|
|
21
|
-
language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
|
|
22
|
-
notifier: NOTIFIER
|
|
23
|
-
}.freeze
|
|
24
|
-
|
|
25
|
-
##
|
|
26
|
-
# @return [Integer] the maxium size of the JSON payload in bytes
|
|
27
|
-
MAX_NOTICE_SIZE = 64000
|
|
28
|
-
|
|
29
|
-
##
|
|
30
|
-
# @return [Integer] the maximum size of hashes, arrays and strings in the
|
|
31
|
-
# notice.
|
|
32
|
-
PAYLOAD_MAX_SIZE = 10000
|
|
33
|
-
|
|
34
|
-
##
|
|
35
|
-
# @return [Array<StandardError>] the list of possible exceptions that might
|
|
36
|
-
# be raised when an object is converted to JSON
|
|
37
|
-
JSON_EXCEPTIONS = [
|
|
38
|
-
IOError,
|
|
39
|
-
NotImplementedError,
|
|
40
|
-
JSON::GeneratorError,
|
|
41
|
-
Encoding::UndefinedConversionError
|
|
42
|
-
].freeze
|
|
43
|
-
|
|
44
|
-
# @return [Array<Symbol>] the list of keys that can be be overwritten with
|
|
45
|
-
# {Airbrake::Notice#[]=}
|
|
46
|
-
WRITABLE_KEYS = %i[notifier context environment session params].freeze
|
|
47
|
-
|
|
48
|
-
##
|
|
49
|
-
# @return [Array<Symbol>] parts of a Notice's payload that can be modified
|
|
50
|
-
# by the truncator
|
|
51
|
-
TRUNCATABLE_KEYS = %i[errors environment session params].freeze
|
|
52
|
-
|
|
53
|
-
##
|
|
54
|
-
# @return [String] the name of the host machine
|
|
55
|
-
HOSTNAME = Socket.gethostname.freeze
|
|
56
|
-
|
|
57
|
-
##
|
|
58
|
-
# @return [String]
|
|
59
|
-
DEFAULT_SEVERITY = 'error'.freeze
|
|
60
|
-
|
|
61
|
-
##
|
|
62
|
-
# @since v1.7.0
|
|
63
|
-
# @return [Hash{Symbol=>Object}] the hash with arbitrary objects to be used
|
|
64
|
-
# in filters
|
|
65
|
-
attr_reader :stash
|
|
66
|
-
|
|
67
|
-
def initialize(config, exception, params = {})
|
|
68
|
-
@config = config
|
|
69
|
-
|
|
70
|
-
@payload = {
|
|
71
|
-
errors: NestedException.new(config, exception).as_json,
|
|
72
|
-
context: context,
|
|
73
|
-
environment: {
|
|
74
|
-
program_name: $PROGRAM_NAME
|
|
75
|
-
},
|
|
76
|
-
session: {},
|
|
77
|
-
params: params
|
|
78
|
-
}
|
|
79
|
-
@stash = { exception: exception }
|
|
80
|
-
@truncator = Airbrake::Truncator.new(PAYLOAD_MAX_SIZE)
|
|
81
|
-
|
|
82
|
-
extract_custom_attributes(exception)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
##
|
|
86
|
-
# Converts the notice to JSON. Calls +to_json+ on each object inside
|
|
87
|
-
# notice's payload. Truncates notices, JSON representation of which is
|
|
88
|
-
# bigger than {MAX_NOTICE_SIZE}.
|
|
89
|
-
#
|
|
90
|
-
# @return [Hash{String=>String}, nil]
|
|
91
|
-
def to_json
|
|
92
|
-
loop do
|
|
93
|
-
begin
|
|
94
|
-
json = @payload.to_json
|
|
95
|
-
rescue *JSON_EXCEPTIONS => ex
|
|
96
|
-
@config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")
|
|
97
|
-
else
|
|
98
|
-
return json if json && json.bytesize <= MAX_NOTICE_SIZE
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
break if truncate == 0
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
##
|
|
106
|
-
# Ignores a notice. Ignored notices never reach the Airbrake dashboard.
|
|
107
|
-
#
|
|
108
|
-
# @return [void]
|
|
109
|
-
# @see #ignored?
|
|
110
|
-
# @note Ignored noticed can't be unignored
|
|
111
|
-
def ignore!
|
|
112
|
-
@payload = nil
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
##
|
|
116
|
-
# Checks whether the notice was ignored.
|
|
117
|
-
#
|
|
118
|
-
# @return [Boolean]
|
|
119
|
-
# @see #ignore!
|
|
120
|
-
def ignored?
|
|
121
|
-
@payload.nil?
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
##
|
|
125
|
-
# Reads a value from notice's payload.
|
|
126
|
-
# @return [Object]
|
|
127
|
-
#
|
|
128
|
-
# @raise [Airbrake::Error] if the notice is ignored
|
|
129
|
-
def [](key)
|
|
130
|
-
raise_if_ignored
|
|
131
|
-
@payload[key]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
##
|
|
135
|
-
# Writes a value to the payload hash. Restricts unrecognized
|
|
136
|
-
# writes.
|
|
137
|
-
# @example
|
|
138
|
-
# notice[:params][:my_param] = 'foobar'
|
|
139
|
-
#
|
|
140
|
-
# @return [void]
|
|
141
|
-
# @raise [Airbrake::Error] if the notice is ignored
|
|
142
|
-
# @raise [Airbrake::Error] if the +key+ is not recognized
|
|
143
|
-
# @raise [Airbrake::Error] if the root value is not a Hash
|
|
144
|
-
def []=(key, value)
|
|
145
|
-
raise_if_ignored
|
|
146
|
-
|
|
147
|
-
unless WRITABLE_KEYS.include?(key)
|
|
148
|
-
raise Airbrake::Error,
|
|
149
|
-
":#{key} is not recognized among #{WRITABLE_KEYS}"
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
unless value.respond_to?(:to_hash)
|
|
153
|
-
raise Airbrake::Error, "Got #{value.class} value, wanted a Hash"
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
@payload[key] = value.to_hash
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
private
|
|
160
|
-
|
|
161
|
-
def context
|
|
162
|
-
{
|
|
163
|
-
version: @config.app_version,
|
|
164
|
-
# We ensure that root_directory is always a String, so it can always be
|
|
165
|
-
# converted to JSON in a predictable manner (when it's a Pathname and in
|
|
166
|
-
# Rails environment, it converts to unexpected JSON).
|
|
167
|
-
rootDirectory: @config.root_directory.to_s,
|
|
168
|
-
environment: @config.environment,
|
|
169
|
-
|
|
170
|
-
# Make sure we always send hostname.
|
|
171
|
-
hostname: HOSTNAME,
|
|
172
|
-
|
|
173
|
-
severity: DEFAULT_SEVERITY
|
|
174
|
-
}.merge(CONTEXT).delete_if { |_key, val| val.nil? || val.empty? }
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def raise_if_ignored
|
|
178
|
-
return unless ignored?
|
|
179
|
-
raise Airbrake::Error, 'cannot access ignored notice'
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def truncate
|
|
183
|
-
TRUNCATABLE_KEYS.each { |key| @truncator.truncate(self[key]) }
|
|
184
|
-
|
|
185
|
-
new_max_size = @truncator.reduce_max_size
|
|
186
|
-
if new_max_size == 0
|
|
187
|
-
@config.logger.error(
|
|
188
|
-
"#{LOG_LABEL} truncation failed. File an issue at " \
|
|
189
|
-
"https://github.com/airbrake/airbrake-ruby " \
|
|
190
|
-
"and attach the following payload: #{@payload}"
|
|
191
|
-
)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
new_max_size
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
def extract_custom_attributes(exception)
|
|
198
|
-
return unless exception.respond_to?(:to_airbrake)
|
|
199
|
-
attributes = nil
|
|
200
|
-
|
|
201
|
-
begin
|
|
202
|
-
attributes = exception.to_airbrake
|
|
203
|
-
rescue StandardError => ex
|
|
204
|
-
@config.logger.error(
|
|
205
|
-
"#{LOG_LABEL} #{exception.class}#to_airbrake failed: #{ex.class}: #{ex}"
|
|
206
|
-
)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
return unless attributes
|
|
210
|
-
|
|
211
|
-
begin
|
|
212
|
-
@payload.merge!(attributes)
|
|
213
|
-
rescue TypeError
|
|
214
|
-
@config.logger.error(
|
|
215
|
-
"#{LOG_LABEL} #{exception.class}#to_airbrake failed:" \
|
|
216
|
-
" #{attributes} must be a Hash"
|
|
217
|
-
)
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
end
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line
|
data/spec/helpers.rb
DELETED
data/spec/ignorable_spec.rb
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::Ignorable do
|
|
2
|
-
let(:klass) do
|
|
3
|
-
mod = subject
|
|
4
|
-
Class.new { include(mod) }
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
it "ignores includee" do
|
|
8
|
-
instance = klass.new
|
|
9
|
-
expect(instance).not_to be_ignored
|
|
10
|
-
|
|
11
|
-
instance.ignore!
|
|
12
|
-
expect(instance).to be_ignored
|
|
13
|
-
end
|
|
14
|
-
end
|
data/spec/inspectable_spec.rb
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::Inspectable do
|
|
2
|
-
let(:klass) do
|
|
3
|
-
mod = subject
|
|
4
|
-
Class.new do
|
|
5
|
-
include(mod)
|
|
6
|
-
|
|
7
|
-
def initialize
|
|
8
|
-
@config = Airbrake::Config.new
|
|
9
|
-
@filter_chain = nil
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe "#inspect" do
|
|
15
|
-
it "displays object information" do
|
|
16
|
-
instance = klass.new
|
|
17
|
-
expect(instance.inspect).to match(/
|
|
18
|
-
#<:0x\w+\s
|
|
19
|
-
project_id=""\s
|
|
20
|
-
project_key=""\s
|
|
21
|
-
host="http.+"\s
|
|
22
|
-
filter_chain=nil>
|
|
23
|
-
/x)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
describe "#pretty_print" do
|
|
28
|
-
it "displays object information in a beautiful way" do
|
|
29
|
-
q = PP.new
|
|
30
|
-
|
|
31
|
-
instance = klass.new
|
|
32
|
-
# Guarding is needed to fix JRuby failure:
|
|
33
|
-
# NoMethodError: undefined method `[]' for nil:NilClass
|
|
34
|
-
q.guard_inspect_key { instance.pretty_print(q) }
|
|
35
|
-
|
|
36
|
-
expect(q.output).to match(/
|
|
37
|
-
#<:0x\w+\s
|
|
38
|
-
project_id=""\s
|
|
39
|
-
project_key=""\s
|
|
40
|
-
host="http.+"\s
|
|
41
|
-
filter_chain=nil
|
|
42
|
-
/x)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
data/spec/monotonic_time_spec.rb
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::MonotonicTime do
|
|
2
|
-
describe ".time_in_ms" do
|
|
3
|
-
it "returns monotonic time in milliseconds" do
|
|
4
|
-
expect(subject.time_in_ms).to be_a(Float)
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
it "always returns time in the future" do
|
|
8
|
-
old_time = subject.time_in_ms
|
|
9
|
-
expect(subject.time_in_ms).to be > old_time
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::NestedException do
|
|
2
|
-
describe "#as_json" do
|
|
3
|
-
context "given exceptions with backtraces" do
|
|
4
|
-
it "unwinds nested exceptions" do
|
|
5
|
-
begin
|
|
6
|
-
begin
|
|
7
|
-
raise AirbrakeTestError
|
|
8
|
-
rescue AirbrakeTestError
|
|
9
|
-
Ruby21Error.raise_error('bingo')
|
|
10
|
-
end
|
|
11
|
-
rescue Ruby21Error => ex
|
|
12
|
-
nested_exception = described_class.new(ex)
|
|
13
|
-
exceptions = nested_exception.as_json
|
|
14
|
-
|
|
15
|
-
expect(exceptions.size).to eq(2)
|
|
16
|
-
expect(exceptions[0][:message]).to eq('bingo')
|
|
17
|
-
expect(exceptions[1][:message]).to eq('App crashed!')
|
|
18
|
-
expect(exceptions[0][:backtrace]).not_to be_empty
|
|
19
|
-
expect(exceptions[1][:backtrace]).not_to be_empty
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "unwinds no more than 3 nested exceptions" do
|
|
24
|
-
begin
|
|
25
|
-
begin
|
|
26
|
-
raise AirbrakeTestError
|
|
27
|
-
rescue AirbrakeTestError
|
|
28
|
-
begin
|
|
29
|
-
Ruby21Error.raise_error('bongo')
|
|
30
|
-
rescue Ruby21Error
|
|
31
|
-
begin
|
|
32
|
-
Ruby21Error.raise_error('bango')
|
|
33
|
-
rescue Ruby21Error
|
|
34
|
-
Ruby21Error.raise_error('bingo')
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
rescue Ruby21Error => ex
|
|
39
|
-
nested_exception = described_class.new(ex)
|
|
40
|
-
exceptions = nested_exception.as_json
|
|
41
|
-
|
|
42
|
-
expect(exceptions.size).to eq(3)
|
|
43
|
-
expect(exceptions[0][:message]).to eq('bingo')
|
|
44
|
-
expect(exceptions[1][:message]).to eq('bango')
|
|
45
|
-
expect(exceptions[2][:message]).to eq('bongo')
|
|
46
|
-
expect(exceptions[0][:backtrace]).not_to be_empty
|
|
47
|
-
expect(exceptions[1][:backtrace]).not_to be_empty
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
context "given exceptions without backtraces" do
|
|
53
|
-
it "sets backtrace to nil" do
|
|
54
|
-
begin
|
|
55
|
-
begin
|
|
56
|
-
raise AirbrakeTestError
|
|
57
|
-
rescue AirbrakeTestError => ex2
|
|
58
|
-
ex2.set_backtrace([])
|
|
59
|
-
Ruby21Error.raise_error('bingo')
|
|
60
|
-
end
|
|
61
|
-
rescue Ruby21Error => ex1
|
|
62
|
-
ex1.set_backtrace([])
|
|
63
|
-
nested_exception = described_class.new(ex1)
|
|
64
|
-
exceptions = nested_exception.as_json
|
|
65
|
-
|
|
66
|
-
expect(exceptions.size).to eq(2)
|
|
67
|
-
expect(exceptions[0][:backtrace]).to be_empty
|
|
68
|
-
expect(exceptions[1][:backtrace]).to be_empty
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|