airbrake-ruby 4.5.1 → 4.7.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.rb +2 -0
- data/lib/airbrake-ruby/async_sender.rb +21 -83
- data/lib/airbrake-ruby/config.rb +24 -3
- data/lib/airbrake-ruby/file_cache.rb +6 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +22 -1
- data/lib/airbrake-ruby/performance_breakdown.rb +2 -1
- data/lib/airbrake-ruby/performance_notifier.rb +44 -16
- data/lib/airbrake-ruby/query.rb +2 -1
- data/lib/airbrake-ruby/request.rb +2 -1
- data/lib/airbrake-ruby/thread_pool.rb +128 -0
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/async_sender_spec.rb +32 -115
- data/spec/config_spec.rb +45 -0
- data/spec/{file_cache.rb → file_cache_spec.rb} +2 -4
- data/spec/filters/sql_filter_spec.rb +47 -4
- data/spec/filters/thread_filter_spec.rb +2 -2
- data/spec/{notice_notifier_spec → notice_notifier}/options_spec.rb +0 -0
- data/spec/performance_notifier_spec.rb +64 -28
- data/spec/thread_pool_spec.rb +158 -0
- metadata +9 -6
@@ -245,12 +245,12 @@ RSpec.describe Airbrake::Filters::ThreadFilter do
|
|
245
245
|
|
246
246
|
it "appends thread inspect (self)" do
|
247
247
|
subject.call(notice)
|
248
|
-
expect(notice[:params][:thread][:self]).to match(/\A#<Thread
|
248
|
+
expect(notice[:params][:thread][:self]).to match(/\A#<Thread:.+>\z/)
|
249
249
|
end
|
250
250
|
|
251
251
|
it "appends thread group" do
|
252
252
|
subject.call(notice)
|
253
|
-
expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread
|
253
|
+
expect(notice[:params][:thread][:group][0]).to match(/\A#<Thread:.+>\z/)
|
254
254
|
end
|
255
255
|
|
256
256
|
it "appends priority" do
|
File without changes
|
@@ -12,7 +12,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
12
12
|
project_id: 1,
|
13
13
|
project_key: 'banana',
|
14
14
|
performance_stats: true,
|
15
|
-
performance_stats_flush_period: 0
|
15
|
+
performance_stats_flush_period: 0,
|
16
|
+
query_stats: true
|
16
17
|
)
|
17
18
|
end
|
18
19
|
|
@@ -30,6 +31,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
30
31
|
end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
|
31
32
|
)
|
32
33
|
)
|
34
|
+
subject.close
|
33
35
|
|
34
36
|
expect(
|
35
37
|
a_request(:put, queries).with(body: %r|
|
@@ -59,6 +61,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
59
61
|
end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
|
60
62
|
)
|
61
63
|
)
|
64
|
+
subject.close
|
62
65
|
|
63
66
|
expect(
|
64
67
|
a_request(:put, routes).with(body: %r|
|
@@ -86,6 +89,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
86
89
|
groups: { db: 131, view: 421 }
|
87
90
|
)
|
88
91
|
)
|
92
|
+
subject.close
|
89
93
|
|
90
94
|
expect(
|
91
95
|
a_request(:put, breakdowns).with(body: %r|
|
@@ -125,6 +129,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
125
129
|
start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
|
126
130
|
)
|
127
131
|
)
|
132
|
+
subject.close
|
133
|
+
|
128
134
|
expect(
|
129
135
|
a_request(:put, routes).with(body: /"time":"2018-01-01T00:00:00\+00:00"/)
|
130
136
|
).to have_been_made
|
@@ -147,6 +153,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
147
153
|
start_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
|
148
154
|
)
|
149
155
|
)
|
156
|
+
subject.close
|
157
|
+
|
150
158
|
expect(
|
151
159
|
a_request(:put, routes).with(body: /"count":2/)
|
152
160
|
).to have_been_made
|
@@ -171,6 +179,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
171
179
|
end_time: Time.new(2018, 1, 1, 0, 1, 55, 0)
|
172
180
|
)
|
173
181
|
)
|
182
|
+
subject.close
|
183
|
+
|
174
184
|
expect(
|
175
185
|
a_request(:put, routes).with(
|
176
186
|
body: %r|\A
|
@@ -205,6 +215,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
205
215
|
end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
|
206
216
|
)
|
207
217
|
)
|
218
|
+
subject.close
|
219
|
+
|
208
220
|
expect(
|
209
221
|
a_request(:put, routes).with(
|
210
222
|
body: %r|\A
|
@@ -241,6 +253,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
241
253
|
groups: { db: 55, view: 11 }
|
242
254
|
)
|
243
255
|
)
|
256
|
+
subject.close
|
244
257
|
|
245
258
|
expect(
|
246
259
|
a_request(:put, breakdowns).with(body: %r|
|
@@ -280,38 +293,20 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
280
293
|
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
281
294
|
)
|
282
295
|
)
|
296
|
+
subject.close
|
297
|
+
|
283
298
|
expect(promise).to be_an(Airbrake::Promise)
|
284
299
|
expect(promise.value).to eq('' => nil)
|
285
300
|
end
|
286
301
|
|
287
|
-
it "
|
288
|
-
Airbrake::
|
289
|
-
|
290
|
-
promise = subject.notify(
|
291
|
-
Airbrake::Request.new(
|
292
|
-
method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
|
293
|
-
)
|
294
|
-
)
|
295
|
-
|
296
|
-
expect(a_request(:put, routes)).not_to have_been_made
|
297
|
-
expect(promise.value).to eq(
|
298
|
-
'error' => "The Performance Stats feature is disabled"
|
299
|
-
)
|
300
|
-
end
|
301
|
-
|
302
|
-
it "doesn't send route stats when current environment is ignored" do
|
303
|
-
Airbrake::Config.instance.merge(
|
304
|
-
performance_stats: true, environment: 'test', ignore_environments: %w[test]
|
302
|
+
it "checks performance stat configuration" do
|
303
|
+
request = Airbrake::Request.new(
|
304
|
+
method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
|
305
305
|
)
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
)
|
311
|
-
)
|
312
|
-
|
313
|
-
expect(a_request(:put, routes)).not_to have_been_made
|
314
|
-
expect(promise.value).to eq('error' => "current environment 'test' is ignored")
|
306
|
+
expect(Airbrake::Config.instance).to receive(:check_performance_options)
|
307
|
+
.with(request).and_return(Airbrake::Promise.new)
|
308
|
+
subject.notify(request)
|
309
|
+
subject.close
|
315
310
|
end
|
316
311
|
|
317
312
|
it "sends environment when it's specified" do
|
@@ -325,6 +320,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
325
320
|
start_time: Time.new
|
326
321
|
)
|
327
322
|
)
|
323
|
+
subject.close
|
324
|
+
|
328
325
|
expect(
|
329
326
|
a_request(:put, routes).with(
|
330
327
|
body: /\A{"routes":\[.+\],"environment":"test"}\z/x
|
@@ -389,6 +386,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
389
386
|
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
390
387
|
)
|
391
388
|
)
|
389
|
+
subject.close
|
390
|
+
|
392
391
|
expect(a_request(:put, routes)).not_to have_been_made
|
393
392
|
end
|
394
393
|
|
@@ -401,6 +400,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
401
400
|
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
402
401
|
)
|
403
402
|
)
|
403
|
+
subject.close
|
404
|
+
|
404
405
|
expect(a_request(:put, queries)).not_to have_been_made
|
405
406
|
end
|
406
407
|
end
|
@@ -421,6 +422,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
421
422
|
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
422
423
|
)
|
423
424
|
)
|
425
|
+
subject.close
|
426
|
+
|
424
427
|
expect(
|
425
428
|
a_request(:put, queries).with(
|
426
429
|
body: /\A{"queries":\[{"method":"POST","route":"\[Filtered\]"/
|
@@ -430,6 +433,37 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
430
433
|
end
|
431
434
|
end
|
432
435
|
|
436
|
+
describe "#close" do
|
437
|
+
before do
|
438
|
+
Airbrake::Config.instance.merge(performance_stats_flush_period: 0.1)
|
439
|
+
end
|
440
|
+
|
441
|
+
after do
|
442
|
+
Airbrake::Config.instance.merge(performance_stats_flush_period: 0)
|
443
|
+
end
|
444
|
+
|
445
|
+
it "kills the background thread" do
|
446
|
+
expect_any_instance_of(Thread).to receive(:kill).and_call_original
|
447
|
+
subject.notify(
|
448
|
+
Airbrake::Query.new(
|
449
|
+
method: 'POST',
|
450
|
+
route: '/foo',
|
451
|
+
query: 'SELECT * FROM things',
|
452
|
+
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
453
|
+
)
|
454
|
+
)
|
455
|
+
subject.close
|
456
|
+
end
|
457
|
+
|
458
|
+
it "logs the exit message" do
|
459
|
+
allow(Airbrake::Loggable.instance).to receive(:debug)
|
460
|
+
expect(Airbrake::Loggable.instance).to receive(:debug).with(
|
461
|
+
/performance notifier closed/
|
462
|
+
)
|
463
|
+
subject.close
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
433
467
|
describe "#delete_filter" do
|
434
468
|
let(:filter) do
|
435
469
|
Class.new do
|
@@ -449,6 +483,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
449
483
|
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
450
484
|
)
|
451
485
|
)
|
486
|
+
subject.close
|
487
|
+
|
452
488
|
expect(a_request(:put, routes)).to have_been_made
|
453
489
|
end
|
454
490
|
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
RSpec.describe Airbrake::ThreadPool do
|
2
|
+
let(:tasks) { [] }
|
3
|
+
let(:worker_size) { 1 }
|
4
|
+
let(:queue_size) { 2 }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
worker_size: worker_size,
|
9
|
+
queue_size: queue_size,
|
10
|
+
block: proc { |message| tasks << message }
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#<<" do
|
15
|
+
it "returns true" do
|
16
|
+
retval = subject << 1
|
17
|
+
subject.close
|
18
|
+
expect(retval).to eq(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "performs work in background" do
|
22
|
+
subject << 2
|
23
|
+
subject << 1
|
24
|
+
subject.close
|
25
|
+
|
26
|
+
expect(tasks).to eq([2, 1])
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the queue is full" do
|
30
|
+
before do
|
31
|
+
allow(subject).to receive(:backlog).and_return(queue_size)
|
32
|
+
end
|
33
|
+
|
34
|
+
subject do
|
35
|
+
described_class.new(
|
36
|
+
worker_size: 1,
|
37
|
+
queue_size: 1,
|
38
|
+
block: proc { |message| tasks << message }
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns false" do
|
43
|
+
retval = subject << 1
|
44
|
+
subject.close
|
45
|
+
expect(retval).to eq(false)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "discards tasks" do
|
49
|
+
200.times { subject << 1 }
|
50
|
+
subject.close
|
51
|
+
|
52
|
+
expect(tasks.size).to be_zero
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#backlog" do
|
58
|
+
let(:worker_size) { 0 }
|
59
|
+
|
60
|
+
it "returns the size of the queue" do
|
61
|
+
subject << 1
|
62
|
+
expect(subject.backlog).to eq(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#has_workers?" do
|
67
|
+
it "returns false when the thread pool is not closed, but has 0 workers" do
|
68
|
+
subject.workers.list.each do |worker|
|
69
|
+
worker.kill.join
|
70
|
+
end
|
71
|
+
expect(subject).not_to have_workers
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns false when the thread pool is closed" do
|
75
|
+
subject.close
|
76
|
+
expect(subject).not_to have_workers
|
77
|
+
end
|
78
|
+
|
79
|
+
it "respawns workers on fork()", skip: %w[jruby].include?(RUBY_ENGINE) do
|
80
|
+
pid = fork { expect(subject).to have_workers }
|
81
|
+
Process.wait(pid)
|
82
|
+
subject.close
|
83
|
+
expect(subject).not_to have_workers
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#close" do
|
88
|
+
context "when there's no work to do" do
|
89
|
+
it "joins the spawned thread" do
|
90
|
+
workers = subject.workers.list
|
91
|
+
expect(workers).to all(be_alive)
|
92
|
+
|
93
|
+
subject.close
|
94
|
+
expect(workers).to all(be_stop)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when there's some work to do" do
|
99
|
+
it "logs how many tasks are left to process" do
|
100
|
+
thread_pool = described_class.new(
|
101
|
+
worker_size: 0, queue_size: 2, block: proc {}
|
102
|
+
)
|
103
|
+
|
104
|
+
expect(Airbrake::Loggable.instance).to receive(:debug).with(
|
105
|
+
/waiting to process \d+ task\(s\)/
|
106
|
+
)
|
107
|
+
expect(Airbrake::Loggable.instance).to receive(:debug).with(/closed/)
|
108
|
+
|
109
|
+
2.times { thread_pool << 1 }
|
110
|
+
thread_pool.close
|
111
|
+
end
|
112
|
+
|
113
|
+
it "waits until the queue gets empty" do
|
114
|
+
thread_pool = described_class.new(
|
115
|
+
worker_size: 1, queue_size: 2, block: proc {}
|
116
|
+
)
|
117
|
+
|
118
|
+
10.times { subject << 1 }
|
119
|
+
thread_pool.close
|
120
|
+
expect(thread_pool.backlog).to be_zero
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when it was already closed" do
|
125
|
+
it "doesn't increase the queue size" do
|
126
|
+
begin
|
127
|
+
subject.close
|
128
|
+
rescue Airbrake::Error
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
|
132
|
+
expect(subject.backlog).to be_zero
|
133
|
+
end
|
134
|
+
|
135
|
+
it "raises error" do
|
136
|
+
subject.close
|
137
|
+
expect { subject.close }.to raise_error(
|
138
|
+
Airbrake::Error, 'this thread pool is closed already'
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "#spawn_workers" do
|
145
|
+
it "spawns alive threads in an enclosed ThreadGroup" do
|
146
|
+
expect(subject.workers).to be_a(ThreadGroup)
|
147
|
+
expect(subject.workers.list).to all(be_alive)
|
148
|
+
expect(subject.workers).to be_enclosed
|
149
|
+
|
150
|
+
subject.close
|
151
|
+
end
|
152
|
+
|
153
|
+
it "spawns exactly `workers_size` workers" do
|
154
|
+
expect(subject.workers.list.size).to eq(worker_size)
|
155
|
+
subject.close
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.7.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-
|
11
|
+
date: 2019-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbtree3
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- lib/airbrake-ruby/stat.rb
|
81
81
|
- lib/airbrake-ruby/sync_sender.rb
|
82
82
|
- lib/airbrake-ruby/tdigest.rb
|
83
|
+
- lib/airbrake-ruby/thread_pool.rb
|
83
84
|
- lib/airbrake-ruby/time_truncate.rb
|
84
85
|
- lib/airbrake-ruby/timed_trace.rb
|
85
86
|
- lib/airbrake-ruby/truncator.rb
|
@@ -92,7 +93,7 @@ files:
|
|
92
93
|
- spec/config/validator_spec.rb
|
93
94
|
- spec/config_spec.rb
|
94
95
|
- spec/deploy_notifier_spec.rb
|
95
|
-
- spec/
|
96
|
+
- spec/file_cache_spec.rb
|
96
97
|
- spec/filter_chain_spec.rb
|
97
98
|
- spec/filters/context_filter_spec.rb
|
98
99
|
- spec/filters/dependency_filter_spec.rb
|
@@ -118,8 +119,8 @@ files:
|
|
118
119
|
- spec/inspectable_spec.rb
|
119
120
|
- spec/monotonic_time_spec.rb
|
120
121
|
- spec/nested_exception_spec.rb
|
122
|
+
- spec/notice_notifier/options_spec.rb
|
121
123
|
- spec/notice_notifier_spec.rb
|
122
|
-
- spec/notice_notifier_spec/options_spec.rb
|
123
124
|
- spec/notice_spec.rb
|
124
125
|
- spec/performance_breakdown_spec.rb
|
125
126
|
- spec/performance_notifier_spec.rb
|
@@ -132,6 +133,7 @@ files:
|
|
132
133
|
- spec/stat_spec.rb
|
133
134
|
- spec/sync_sender_spec.rb
|
134
135
|
- spec/tdigest_spec.rb
|
136
|
+
- spec/thread_pool_spec.rb
|
135
137
|
- spec/time_truncate_spec.rb
|
136
138
|
- spec/timed_trace_spec.rb
|
137
139
|
- spec/truncator_spec.rb
|
@@ -187,6 +189,7 @@ test_files:
|
|
187
189
|
- spec/notice_notifier_spec.rb
|
188
190
|
- spec/time_truncate_spec.rb
|
189
191
|
- spec/promise_spec.rb
|
192
|
+
- spec/thread_pool_spec.rb
|
190
193
|
- spec/config/validator_spec.rb
|
191
194
|
- spec/sync_sender_spec.rb
|
192
195
|
- spec/ignorable_spec.rb
|
@@ -195,10 +198,11 @@ test_files:
|
|
195
198
|
- spec/airbrake_spec.rb
|
196
199
|
- spec/nested_exception_spec.rb
|
197
200
|
- spec/timed_trace_spec.rb
|
201
|
+
- spec/file_cache_spec.rb
|
198
202
|
- spec/request_spec.rb
|
203
|
+
- spec/notice_notifier/options_spec.rb
|
199
204
|
- spec/filter_chain_spec.rb
|
200
205
|
- spec/response_spec.rb
|
201
|
-
- spec/file_cache.rb
|
202
206
|
- spec/code_hunk_spec.rb
|
203
207
|
- spec/fixtures/notroot.txt
|
204
208
|
- spec/fixtures/project_root/long_line.txt
|
@@ -210,4 +214,3 @@ test_files:
|
|
210
214
|
- spec/inspectable_spec.rb
|
211
215
|
- spec/stashable_spec.rb
|
212
216
|
- spec/query_spec.rb
|
213
|
-
- spec/notice_notifier_spec/options_spec.rb
|