airbrake-ruby 3.1.0 → 3.2.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.
- checksums.yaml +4 -4
- data/lib/airbrake-ruby.rb +197 -43
- data/lib/airbrake-ruby/config.rb +43 -11
- data/lib/airbrake-ruby/deploy_notifier.rb +47 -0
- data/lib/airbrake-ruby/filter_chain.rb +32 -50
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +9 -1
- data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
- data/lib/airbrake-ruby/hash_keyable.rb +37 -0
- data/lib/airbrake-ruby/ignorable.rb +44 -0
- data/lib/airbrake-ruby/notice.rb +2 -22
- data/lib/airbrake-ruby/{notifier.rb → notice_notifier.rb} +66 -46
- data/lib/airbrake-ruby/performance_notifier.rb +161 -0
- data/lib/airbrake-ruby/stat.rb +56 -0
- data/lib/airbrake-ruby/tdigest.rb +393 -0
- data/lib/airbrake-ruby/time_truncate.rb +17 -0
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/airbrake_spec.rb +57 -13
- data/spec/async_sender_spec.rb +0 -2
- data/spec/backtrace_spec.rb +0 -2
- data/spec/code_hunk_spec.rb +0 -2
- data/spec/config/validator_spec.rb +0 -2
- data/spec/config_spec.rb +16 -4
- data/spec/deploy_notifier_spec.rb +41 -0
- data/spec/file_cache.rb +0 -2
- data/spec/filter_chain_spec.rb +1 -7
- data/spec/filters/context_filter_spec.rb +0 -2
- data/spec/filters/dependency_filter_spec.rb +0 -2
- data/spec/filters/exception_attributes_filter_spec.rb +0 -2
- data/spec/filters/gem_root_filter_spec.rb +0 -2
- data/spec/filters/git_last_checkout_filter_spec.rb +0 -2
- data/spec/filters/git_repository_filter.rb +0 -2
- data/spec/filters/git_revision_filter_spec.rb +0 -2
- data/spec/filters/keys_blacklist_spec.rb +0 -2
- data/spec/filters/keys_whitelist_spec.rb +0 -2
- data/spec/filters/root_directory_filter_spec.rb +0 -2
- data/spec/filters/sql_filter_spec.rb +219 -0
- data/spec/filters/system_exit_filter_spec.rb +0 -2
- data/spec/filters/thread_filter_spec.rb +0 -2
- data/spec/ignorable_spec.rb +14 -0
- data/spec/nested_exception_spec.rb +0 -2
- data/spec/{notifier_spec.rb → notice_notifier_spec.rb} +24 -114
- data/spec/{notifier_spec → notice_notifier_spec}/options_spec.rb +40 -39
- data/spec/notice_spec.rb +2 -4
- data/spec/performance_notifier_spec.rb +287 -0
- data/spec/promise_spec.rb +0 -2
- data/spec/response_spec.rb +0 -2
- data/spec/stat_spec.rb +35 -0
- data/spec/sync_sender_spec.rb +0 -2
- data/spec/tdigest_spec.rb +230 -0
- data/spec/time_truncate_spec.rb +13 -0
- data/spec/truncator_spec.rb +0 -2
- metadata +34 -15
- data/lib/airbrake-ruby/route_sender.rb +0 -175
- data/spec/route_sender_spec.rb +0 -130
@@ -0,0 +1,14 @@
|
|
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
|
@@ -1,17 +1,17 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
# rubocop:disable Layout/DotPosition
|
4
|
-
RSpec.describe Airbrake::
|
2
|
+
RSpec.describe Airbrake::NoticeNotifier do
|
5
3
|
let(:user_params) do
|
6
4
|
{
|
7
5
|
project_id: 1,
|
8
6
|
project_key: 'abc',
|
9
7
|
logger: Logger.new('/dev/null'),
|
10
|
-
|
8
|
+
performance_stats: true
|
11
9
|
}
|
12
10
|
end
|
13
11
|
|
14
|
-
|
12
|
+
let(:params) { {} }
|
13
|
+
let(:config) { Airbrake::Config.new(user_params.merge(params)) }
|
14
|
+
subject { described_class.new(config) }
|
15
15
|
|
16
16
|
describe "#new" do
|
17
17
|
describe "default filter addition" do
|
@@ -20,20 +20,22 @@ RSpec.describe Airbrake::Notifier do
|
|
20
20
|
it "appends the context filter" do
|
21
21
|
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
22
22
|
.with(instance_of(Airbrake::Filters::ContextFilter))
|
23
|
-
|
23
|
+
subject
|
24
24
|
end
|
25
25
|
|
26
26
|
it "appends the exception attributes filter" do
|
27
27
|
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
28
28
|
.with(instance_of(Airbrake::Filters::ExceptionAttributesFilter))
|
29
|
-
|
29
|
+
subject
|
30
30
|
end
|
31
31
|
|
32
32
|
context "when user config has some whitelist keys" do
|
33
|
+
let(:params) { { whitelist_keys: %w[foo] } }
|
34
|
+
|
33
35
|
it "appends the whitelist filter" do
|
34
36
|
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
35
37
|
.with(instance_of(Airbrake::Filters::KeysWhitelist))
|
36
|
-
described_class.new(
|
38
|
+
described_class.new(config)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
@@ -41,15 +43,17 @@ RSpec.describe Airbrake::Notifier do
|
|
41
43
|
it "doesn't append the whitelist filter" do
|
42
44
|
expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
|
43
45
|
.with(instance_of(Airbrake::Filters::KeysWhitelist))
|
44
|
-
described_class.new(
|
46
|
+
described_class.new(config)
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
50
|
context "when user config has some blacklist keys" do
|
51
|
+
let(:params) { { blacklist_keys: %w[bar] } }
|
52
|
+
|
49
53
|
it "appends the blacklist filter" do
|
50
54
|
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
51
55
|
.with(instance_of(Airbrake::Filters::KeysBlacklist))
|
52
|
-
described_class.new(
|
56
|
+
described_class.new(config)
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
@@ -57,15 +61,17 @@ RSpec.describe Airbrake::Notifier do
|
|
57
61
|
it "doesn't append the blacklist filter" do
|
58
62
|
expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
|
59
63
|
.with(instance_of(Airbrake::Filters::KeysBlacklist))
|
60
|
-
described_class.new(
|
64
|
+
described_class.new(config)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
64
68
|
context "when user config specifies a root directory" do
|
69
|
+
let(:params) { { root_directory: '/foo' } }
|
70
|
+
|
65
71
|
it "appends the root directory filter" do
|
66
72
|
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
67
73
|
.with(instance_of(Airbrake::Filters::RootDirectoryFilter))
|
68
|
-
described_class.new(
|
74
|
+
described_class.new(config)
|
69
75
|
end
|
70
76
|
end
|
71
77
|
|
@@ -75,34 +81,16 @@ RSpec.describe Airbrake::Notifier do
|
|
75
81
|
.and_return(nil)
|
76
82
|
expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
|
77
83
|
.with(instance_of(Airbrake::Filters::RootDirectoryFilter))
|
78
|
-
described_class.new(
|
84
|
+
described_class.new(config)
|
79
85
|
end
|
80
86
|
end
|
81
87
|
end
|
82
|
-
|
83
|
-
context "when user config doesn't contain a project id" do
|
84
|
-
let(:user_config) { { project_id: nil } }
|
85
|
-
|
86
|
-
it "raises error" do
|
87
|
-
expect { described_class.new(user_config) }
|
88
|
-
.to raise_error(Airbrake::Error, ':project_id is required')
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context "when user config doesn't contain a project key" do
|
93
|
-
let(:user_config) { { project_id: 1, project_key: nil } }
|
94
|
-
|
95
|
-
it "raises error" do
|
96
|
-
expect { described_class.new(user_config) }
|
97
|
-
.to raise_error(Airbrake::Error, ':project_key is required')
|
98
|
-
end
|
99
|
-
end
|
100
88
|
end
|
101
89
|
|
102
90
|
describe "#notify" do
|
103
91
|
let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/1/notices' }
|
104
92
|
|
105
|
-
subject { described_class.new(user_params) }
|
93
|
+
subject { described_class.new(Airbrake::Config.new(user_params)) }
|
106
94
|
|
107
95
|
let(:body) do
|
108
96
|
{
|
@@ -173,11 +161,7 @@ RSpec.describe Airbrake::Notifier do
|
|
173
161
|
end
|
174
162
|
|
175
163
|
context "when the provided environment is ignored" do
|
176
|
-
|
177
|
-
described_class.new(
|
178
|
-
user_params.merge(environment: 'test', ignore_environments: ['test'])
|
179
|
-
)
|
180
|
-
end
|
164
|
+
let(:user_params) { { environment: 'test', ignore_environments: %w[test] } }
|
181
165
|
|
182
166
|
it "doesn't send an notice" do
|
183
167
|
expect_any_instance_of(Airbrake::AsyncSender).not_to receive(:send)
|
@@ -257,11 +241,7 @@ RSpec.describe Airbrake::Notifier do
|
|
257
241
|
end
|
258
242
|
|
259
243
|
context "when the provided environment is ignored" do
|
260
|
-
|
261
|
-
described_class.new(
|
262
|
-
user_params.merge(environment: 'test', ignore_environments: ['test'])
|
263
|
-
)
|
264
|
-
end
|
244
|
+
let(:params) { { environment: 'test', ignore_environments: %w[test] } }
|
265
245
|
|
266
246
|
it "doesn't send an notice" do
|
267
247
|
expect_any_instance_of(Airbrake::SyncSender).not_to receive(:send)
|
@@ -412,38 +392,6 @@ RSpec.describe Airbrake::Notifier do
|
|
412
392
|
end
|
413
393
|
end
|
414
394
|
|
415
|
-
describe "#create_deploy" do
|
416
|
-
it "returns a promise" do
|
417
|
-
stub_request(:post, 'https://api.airbrake.io/api/v4/projects/1/deploys')
|
418
|
-
.to_return(status: 201, body: '')
|
419
|
-
expect(subject.create_deploy({})).to be_an(Airbrake::Promise)
|
420
|
-
end
|
421
|
-
|
422
|
-
context "when environment is configured" do
|
423
|
-
it "prefers the passed environment to the config env" do
|
424
|
-
expect_any_instance_of(Airbrake::SyncSender).to receive(:send).with(
|
425
|
-
{ environment: 'barenv' },
|
426
|
-
instance_of(Airbrake::Promise),
|
427
|
-
URI('https://api.airbrake.io/api/v4/projects/1/deploys')
|
428
|
-
)
|
429
|
-
described_class.new(
|
430
|
-
user_params.merge(environment: 'fooenv')
|
431
|
-
).create_deploy(environment: 'barenv')
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
context "when environment is not configured" do
|
436
|
-
it "sets the environment from the config" do
|
437
|
-
expect_any_instance_of(Airbrake::SyncSender).to receive(:send).with(
|
438
|
-
{ environment: 'fooenv' },
|
439
|
-
instance_of(Airbrake::Promise),
|
440
|
-
URI('https://api.airbrake.io/api/v4/projects/1/deploys')
|
441
|
-
)
|
442
|
-
subject.create_deploy(environment: 'fooenv')
|
443
|
-
end
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
395
|
describe "#configured?" do
|
448
396
|
it { is_expected.to be_configured }
|
449
397
|
end
|
@@ -455,48 +403,10 @@ RSpec.describe Airbrake::Notifier do
|
|
455
403
|
end
|
456
404
|
end
|
457
405
|
|
458
|
-
describe "#notify_request" do
|
459
|
-
let(:params) do
|
460
|
-
{
|
461
|
-
method: 'GET',
|
462
|
-
route: '/foo',
|
463
|
-
status_code: 200,
|
464
|
-
start_time: Time.new(2018, 1, 1, 0, 20, 0, 0),
|
465
|
-
end_time: Time.new(2018, 1, 1, 0, 19, 0, 0)
|
466
|
-
}
|
467
|
-
end
|
468
|
-
|
469
|
-
it "forwards 'notify_request' to RouteSender" do
|
470
|
-
expect_any_instance_of(Airbrake::RouteSender)
|
471
|
-
.to receive(:notify_request).with(params, instance_of(Airbrake::Promise))
|
472
|
-
subject.notify_request(params)
|
473
|
-
end
|
474
|
-
|
475
|
-
context "when route stats are disabled" do
|
476
|
-
it "doesn't send route stats" do
|
477
|
-
notifier = described_class.new(user_params.merge(route_stats: false))
|
478
|
-
expect_any_instance_of(Airbrake::RouteSender)
|
479
|
-
.not_to receive(:notify_request)
|
480
|
-
notifier.notify_request(params)
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
context "when current environment is ignored" do
|
485
|
-
it "doesn't send route stats" do
|
486
|
-
notifier = described_class.new(
|
487
|
-
user_params.merge(environment: 'test', ignore_environments: %w[test])
|
488
|
-
)
|
489
|
-
expect_any_instance_of(Airbrake::RouteSender)
|
490
|
-
.not_to receive(:notify_request)
|
491
|
-
notifier.notify_request(params)
|
492
|
-
end
|
493
|
-
end
|
494
|
-
end
|
495
|
-
|
496
406
|
describe "#inspect" do
|
497
407
|
it "displays object information" do
|
498
408
|
expect(subject.inspect).to match(/
|
499
|
-
#<Airbrake::
|
409
|
+
#<Airbrake::NoticeNotifier:0x\w+\s
|
500
410
|
project_id="\d+"\s
|
501
411
|
project_key=".+"\s
|
502
412
|
host="http.+"\s
|
@@ -514,7 +424,7 @@ RSpec.describe Airbrake::Notifier do
|
|
514
424
|
q.guard_inspect_key { subject.pretty_print(q) }
|
515
425
|
|
516
426
|
expect(q.output).to match(/
|
517
|
-
#<Airbrake::
|
427
|
+
#<Airbrake::NoticeNotifier:0x\w+\s
|
518
428
|
project_id="\d+"\s
|
519
429
|
project_key=".+"\s
|
520
430
|
host="http.+"\s
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
RSpec.describe Airbrake::Notifier do
|
1
|
+
RSpec.describe Airbrake::NoticeNotifier do
|
4
2
|
def expect_a_request_with_body(body)
|
5
3
|
expect(a_request(:post, endpoint).with(body: body)).to have_been_made.once
|
6
4
|
end
|
@@ -13,27 +11,31 @@ RSpec.describe Airbrake::Notifier do
|
|
13
11
|
"https://api.airbrake.io/api/v3/projects/#{project_id}/notices"
|
14
12
|
end
|
15
13
|
|
16
|
-
let(:
|
14
|
+
let(:user_params) do
|
17
15
|
{ project_id: project_id,
|
18
16
|
project_key: project_key,
|
19
17
|
logger: Logger.new(StringIO.new) }
|
20
18
|
end
|
21
19
|
|
20
|
+
let(:params) { {} }
|
22
21
|
let(:ex) { AirbrakeTestError.new }
|
22
|
+
let(:config) { Airbrake::Config.new(user_params.merge(params)) }
|
23
|
+
|
24
|
+
subject { described_class.new(config) }
|
23
25
|
|
24
26
|
before do
|
25
27
|
stub_request(:post, endpoint).to_return(status: 201, body: '{}')
|
26
|
-
@airbrake = described_class.new(airbrake_params)
|
27
28
|
end
|
28
29
|
|
29
30
|
describe "options" do
|
30
31
|
describe ":host" do
|
31
32
|
context "when custom" do
|
32
33
|
shared_examples 'endpoint' do |host, endpoint, title|
|
34
|
+
let(:params) { { host: host } }
|
35
|
+
|
33
36
|
example(title) do
|
34
37
|
stub_request(:post, endpoint).to_return(status: 201, body: '{}')
|
35
|
-
|
36
|
-
@airbrake.notify_sync(ex)
|
38
|
+
subject.notify_sync(ex)
|
37
39
|
|
38
40
|
expect(a_request(:post, endpoint)).to have_been_made.once
|
39
41
|
end
|
@@ -68,9 +70,10 @@ RSpec.describe Airbrake::Notifier do
|
|
68
70
|
end
|
69
71
|
|
70
72
|
describe ":root_directory" do
|
73
|
+
let(:params) { { root_directory: '/home/kyrylo/code' } }
|
74
|
+
|
71
75
|
it "filters out frames" do
|
72
|
-
|
73
|
-
airbrake = described_class.new(params)
|
76
|
+
airbrake = described_class.new(config)
|
74
77
|
airbrake.notify_sync(ex)
|
75
78
|
|
76
79
|
expect(
|
@@ -81,11 +84,10 @@ RSpec.describe Airbrake::Notifier do
|
|
81
84
|
|
82
85
|
context "when present and is a" do
|
83
86
|
shared_examples 'root directory' do |dir|
|
84
|
-
|
85
|
-
params = airbrake_params.merge(root_directory: dir)
|
86
|
-
airbrake = described_class.new(params)
|
87
|
-
airbrake.notify_sync(ex)
|
87
|
+
let(:params) { { root_directory: dir } }
|
88
88
|
|
89
|
+
it "being included into the notice's payload" do
|
90
|
+
subject.notify_sync(ex)
|
89
91
|
expect(
|
90
92
|
a_request(:post, endpoint).
|
91
93
|
with(body: %r{"rootDirectory":"/bingo/bango"})
|
@@ -121,6 +123,13 @@ RSpec.describe Airbrake::Notifier do
|
|
121
123
|
password: 'password' }
|
122
124
|
end
|
123
125
|
|
126
|
+
let(:params) do
|
127
|
+
{
|
128
|
+
proxy: proxy_params,
|
129
|
+
host: "http://localhost:#{proxy.config[:Port]}"
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
124
133
|
before do
|
125
134
|
proxy.mount_proc '/' do |req, res|
|
126
135
|
requests << req
|
@@ -129,13 +138,6 @@ RSpec.describe Airbrake::Notifier do
|
|
129
138
|
end
|
130
139
|
|
131
140
|
Thread.new { proxy.start }
|
132
|
-
|
133
|
-
params = airbrake_params.merge(
|
134
|
-
proxy: proxy_params,
|
135
|
-
host: "http://localhost:#{proxy.config[:Port]}"
|
136
|
-
)
|
137
|
-
|
138
|
-
@airbrake = described_class.new(params)
|
139
141
|
end
|
140
142
|
|
141
143
|
after { proxy.stop }
|
@@ -147,7 +149,7 @@ RSpec.describe Airbrake::Notifier do
|
|
147
149
|
"safe to run this test on 2.6+ once we upgrade to Webmock 3.5+"
|
148
150
|
)
|
149
151
|
end
|
150
|
-
|
152
|
+
subject.notify_sync(ex)
|
151
153
|
|
152
154
|
proxied_request = requests.pop(true)
|
153
155
|
|
@@ -163,11 +165,10 @@ RSpec.describe Airbrake::Notifier do
|
|
163
165
|
|
164
166
|
describe ":environment" do
|
165
167
|
context "when present" do
|
166
|
-
|
167
|
-
params = airbrake_params.merge(environment: :production)
|
168
|
-
airbrake = described_class.new(params)
|
169
|
-
airbrake.notify_sync(ex)
|
168
|
+
let(:params) { { environment: :production } }
|
170
169
|
|
170
|
+
it "being included into the notice's payload" do
|
171
|
+
subject.notify_sync(ex)
|
171
172
|
expect(
|
172
173
|
a_request(:post, endpoint).
|
173
174
|
with(body: /"context":{.*"environment":"production".*}/)
|
@@ -178,19 +179,19 @@ RSpec.describe Airbrake::Notifier do
|
|
178
179
|
|
179
180
|
describe ":ignore_environments" do
|
180
181
|
shared_examples 'sent notice' do |params|
|
181
|
-
|
182
|
-
airbrake = described_class.new(airbrake_params.merge(params))
|
183
|
-
airbrake.notify_sync(ex)
|
182
|
+
let(:params) { params }
|
184
183
|
|
184
|
+
it "sends a notice" do
|
185
|
+
subject.notify_sync(ex)
|
185
186
|
expect(a_request(:post, endpoint)).to have_been_made
|
186
187
|
end
|
187
188
|
end
|
188
189
|
|
189
190
|
shared_examples 'ignored notice' do |params|
|
190
|
-
|
191
|
-
airbrake = described_class.new(airbrake_params.merge(params))
|
192
|
-
airbrake.notify_sync(ex)
|
191
|
+
let(:params) { params }
|
193
192
|
|
193
|
+
it "ignores exceptions occurring in envs that were not configured" do
|
194
|
+
subject.notify_sync(ex)
|
194
195
|
expect(a_request(:post, endpoint)).not_to have_been_made
|
195
196
|
end
|
196
197
|
end
|
@@ -213,10 +214,8 @@ RSpec.describe Airbrake::Notifier do
|
|
213
214
|
include_examples 'ignored notice', params
|
214
215
|
|
215
216
|
it "returns early and doesn't try to parse the given exception" do
|
216
|
-
airbrake = described_class.new(airbrake_params.merge(params))
|
217
|
-
|
218
217
|
expect(Airbrake::Notice).not_to receive(:new)
|
219
|
-
expect(
|
218
|
+
expect(subject.notify_sync(ex)).
|
220
219
|
to eq('error' => "The 'development' environment is ignored")
|
221
220
|
expect(a_request(:post, endpoint)).not_to have_been_made
|
222
221
|
end
|
@@ -246,15 +245,17 @@ RSpec.describe Airbrake::Notifier do
|
|
246
245
|
# Fixes https://github.com/airbrake/airbrake-ruby/issues/276
|
247
246
|
context "when specified along with :whitelist_keys" do
|
248
247
|
context "and when context payload is present" do
|
249
|
-
|
250
|
-
|
248
|
+
let(:params) do
|
249
|
+
{
|
251
250
|
blacklist_keys: %i[password password_confirmation],
|
252
251
|
whitelist_keys: [:email, /user/i, 'account_id']
|
253
252
|
}
|
254
|
-
|
255
|
-
|
253
|
+
end
|
254
|
+
|
255
|
+
it "sends a notice" do
|
256
|
+
notice = subject.build_notice(ex)
|
256
257
|
notice[:context][:headers] = 'banana'
|
257
|
-
|
258
|
+
subject.notify_sync(notice)
|
258
259
|
|
259
260
|
expect(a_request(:post, endpoint)).to have_been_made
|
260
261
|
end
|