airbrake-ruby 6.0.1 → 6.0.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 +4 -4
- data/lib/airbrake-ruby/config.rb +3 -3
- data/lib/airbrake-ruby/filters/sql_filter.rb +6 -6
- data/lib/airbrake-ruby/performance_notifier.rb +38 -38
- data/lib/airbrake-ruby/stat.rb +1 -1
- data/lib/airbrake-ruby/time_truncate.rb +2 -2
- data/lib/airbrake-ruby/version.rb +1 -1
- data/lib/airbrake-ruby.rb +21 -21
- data/spec/config_spec.rb +8 -8
- data/spec/performance_notifier_spec.rb +3 -3
- data/spec/time_truncate_spec.rb +23 -8
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0310134480c9c13f2e8ab87a4c616768c213b590f98edd38e9c9abbd539a7ba
|
4
|
+
data.tar.gz: 6f5e8d2411eee4e18ff97ef7d89b3c4a1c8ebb3ba5ec14fafe24c25e850672b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6e19e37eca3e38af441560c044ac1472ab06a282c4d8b4873a4c8529b9fb9e9a70634a42b4d0d5fe668ba866649ee115942678e5bbfffa1f60373ccd66e964b
|
7
|
+
data.tar.gz: f8b22c23d2534b1f4dc12dd1b5d8bf970504b297a61421cda6d496ec2f1143ac9eb031e2c1b033e8d8a24b94b634c2a17ea475f9ef13d482be08a419a54b1d98
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -248,14 +248,14 @@ module Airbrake
|
|
248
248
|
|
249
249
|
# @return [Promise] resolved promise if neither of the performance options
|
250
250
|
# reject it, false otherwise
|
251
|
-
def check_performance_options(
|
251
|
+
def check_performance_options(metric)
|
252
252
|
promise = Airbrake::Promise.new
|
253
253
|
|
254
254
|
if !performance_stats
|
255
255
|
promise.reject("The Performance Stats feature is disabled")
|
256
|
-
elsif
|
256
|
+
elsif metric.is_a?(Airbrake::Query) && !query_stats
|
257
257
|
promise.reject("The Query Stats feature is disabled")
|
258
|
-
elsif
|
258
|
+
elsif metric.is_a?(Airbrake::Queue) && !job_stats
|
259
259
|
promise.reject("The Job Stats feature is disabled")
|
260
260
|
else
|
261
261
|
promise
|
@@ -108,20 +108,20 @@ module Airbrake
|
|
108
108
|
@regexp = Regexp.union(features)
|
109
109
|
end
|
110
110
|
|
111
|
-
# @param [Airbrake::Query]
|
112
|
-
def call(
|
113
|
-
return unless
|
111
|
+
# @param [Airbrake::Query] metric
|
112
|
+
def call(metric)
|
113
|
+
return unless metric.respond_to?(:query)
|
114
114
|
|
115
|
-
query =
|
115
|
+
query = metric.query
|
116
116
|
if IGNORED_QUERIES.any? { |q| q =~ query }
|
117
|
-
|
117
|
+
metric.ignore!
|
118
118
|
return
|
119
119
|
end
|
120
120
|
|
121
121
|
q = query.gsub(@regexp, FILTERED)
|
122
122
|
q.gsub!(POST_FILTER, FILTERED) if q =~ POST_FILTER
|
123
123
|
q = ERROR_MSG if UNMATCHED_PAIR[@dialect] =~ q
|
124
|
-
|
124
|
+
metric.query = q
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Airbrake
|
2
|
-
#
|
3
|
-
#
|
2
|
+
# PerformanceNotifier aggregates performance data and periodically sends it to
|
3
|
+
# Airbrake.
|
4
4
|
#
|
5
5
|
# @api public
|
6
6
|
# @since v3.2.0
|
@@ -21,20 +21,20 @@ module Airbrake
|
|
21
21
|
@has_payload = @payload.new_cond
|
22
22
|
end
|
23
23
|
|
24
|
-
# @param [Hash]
|
24
|
+
# @param [Hash] metric
|
25
25
|
# @see Airbrake.notify_query
|
26
26
|
# @see Airbrake.notify_request
|
27
|
-
def notify(
|
27
|
+
def notify(metric)
|
28
28
|
@payload.synchronize do
|
29
|
-
|
29
|
+
send_metric(metric, sync: false)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
# @param [Hash]
|
33
|
+
# @param [Hash] metric
|
34
34
|
# @since v4.10.0
|
35
35
|
# @see Airbrake.notify_queue_sync
|
36
|
-
def notify_sync(
|
37
|
-
|
36
|
+
def notify_sync(metric)
|
37
|
+
send_metric(metric, sync: true).value
|
38
38
|
end
|
39
39
|
|
40
40
|
# @see Airbrake.add_performance_filter
|
@@ -78,16 +78,16 @@ module Airbrake
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
def
|
82
|
-
promise = check_configuration(
|
81
|
+
def send_metric(metric, sync:)
|
82
|
+
promise = check_configuration(metric)
|
83
83
|
return promise if promise.rejected?
|
84
84
|
|
85
|
-
@filter_chain.refine(
|
86
|
-
if
|
87
|
-
return Promise.new.reject("#{
|
85
|
+
@filter_chain.refine(metric)
|
86
|
+
if metric.ignored?
|
87
|
+
return Promise.new.reject("#{metric.class} was ignored by a filter")
|
88
88
|
end
|
89
89
|
|
90
|
-
update_payload(
|
90
|
+
update_payload(metric)
|
91
91
|
if sync || @flush_period == 0
|
92
92
|
send(@sync_sender, @payload, promise)
|
93
93
|
else
|
@@ -96,29 +96,29 @@ module Airbrake
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
def update_payload(
|
100
|
-
if (total_stat = @payload[
|
101
|
-
@payload.key(total_stat).merge(
|
99
|
+
def update_payload(metric)
|
100
|
+
if (total_stat = @payload[metric])
|
101
|
+
@payload.key(total_stat).merge(metric)
|
102
102
|
else
|
103
|
-
@payload[
|
103
|
+
@payload[metric] = { total: Airbrake::Stat.new }
|
104
104
|
end
|
105
105
|
|
106
|
-
@payload[
|
106
|
+
@payload[metric][:total].increment_ms(metric.timing)
|
107
107
|
|
108
|
-
|
109
|
-
@payload[
|
110
|
-
@payload[
|
108
|
+
metric.groups.each do |name, ms|
|
109
|
+
@payload[metric][name] ||= Airbrake::Stat.new
|
110
|
+
@payload[metric][name].increment_ms(ms)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
def check_configuration(
|
114
|
+
def check_configuration(metric)
|
115
115
|
promise = @config.check_configuration
|
116
116
|
return promise if promise.rejected?
|
117
117
|
|
118
|
-
promise = @config.check_performance_options(
|
118
|
+
promise = @config.check_performance_options(metric)
|
119
119
|
return promise if promise.rejected?
|
120
120
|
|
121
|
-
if
|
121
|
+
if metric.timing && metric.timing == 0
|
122
122
|
return Promise.new.reject(':timing cannot be zero')
|
123
123
|
end
|
124
124
|
|
@@ -128,47 +128,47 @@ module Airbrake
|
|
128
128
|
def send(sender, payload, promise)
|
129
129
|
raise "payload cannot be empty. Race?" if payload.none?
|
130
130
|
|
131
|
-
with_grouped_payload(payload) do |
|
131
|
+
with_grouped_payload(payload) do |metric_hash, destination|
|
132
132
|
url = URI.join(
|
133
133
|
@config.apm_host,
|
134
134
|
"api/v5/projects/#{@config.project_id}/#{destination}",
|
135
135
|
)
|
136
136
|
|
137
137
|
logger.debug do
|
138
|
-
"#{LOG_LABEL} #{self.class.name}##{__method__}: #{
|
138
|
+
"#{LOG_LABEL} #{self.class.name}##{__method__}: #{metric_hash}"
|
139
139
|
end
|
140
|
-
sender.send(
|
140
|
+
sender.send(metric_hash, promise, url)
|
141
141
|
end
|
142
142
|
|
143
143
|
promise
|
144
144
|
end
|
145
145
|
|
146
146
|
def with_grouped_payload(raw_payload)
|
147
|
-
grouped_payload = raw_payload.group_by do |
|
148
|
-
[
|
147
|
+
grouped_payload = raw_payload.group_by do |metric, _stats|
|
148
|
+
[metric.cargo, metric.destination]
|
149
149
|
end
|
150
150
|
|
151
|
-
grouped_payload.each do |(cargo, destination),
|
151
|
+
grouped_payload.each do |(cargo, destination), metrics|
|
152
152
|
payload = {}
|
153
|
-
payload[cargo] =
|
153
|
+
payload[cargo] = serialize_metrics(metrics)
|
154
154
|
payload['environment'] = @config.environment if @config.environment
|
155
155
|
|
156
156
|
yield(payload, destination)
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
def
|
161
|
-
|
162
|
-
|
160
|
+
def serialize_metrics(metrics)
|
161
|
+
metrics.map do |metric, stats|
|
162
|
+
metric_hash = metric.to_h.merge!(stats[:total].to_h)
|
163
163
|
|
164
|
-
if
|
164
|
+
if metric.groups.any?
|
165
165
|
group_stats = stats.reject { |name, _stat| name == :total }
|
166
|
-
|
166
|
+
metric_hash['groups'] = group_stats.merge(group_stats) do |_name, stat|
|
167
167
|
stat.to_h
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
|
-
|
171
|
+
metric_hash
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
data/lib/airbrake-ruby/stat.rb
CHANGED
@@ -4,7 +4,7 @@ module Airbrake
|
|
4
4
|
# Stat is a data structure that allows accumulating performance data (route
|
5
5
|
# performance, SQL query performance and such). It's powered by TDigests.
|
6
6
|
#
|
7
|
-
# Usually, one Stat corresponds to one
|
7
|
+
# Usually, one Stat corresponds to one metric (route or query,
|
8
8
|
# etc.). Incrementing a stat means pushing new performance statistics.
|
9
9
|
#
|
10
10
|
# @example
|
@@ -6,10 +6,10 @@ module Airbrake
|
|
6
6
|
module TimeTruncate
|
7
7
|
# Truncate +time+ to floor minute and turn it into an RFC3339 timestamp.
|
8
8
|
#
|
9
|
-
# @param [Time] time
|
9
|
+
# @param [Time, Integer, Float] time
|
10
10
|
# @return [String]
|
11
11
|
def self.utc_truncate_minutes(time)
|
12
|
-
tm = time.getutc
|
12
|
+
tm = Time.at(time).getutc
|
13
13
|
|
14
14
|
Time.utc(tm.year, tm.month, tm.day, tm.hour, tm.min).to_datetime.rfc3339
|
15
15
|
end
|
data/lib/airbrake-ruby.rb
CHANGED
@@ -364,23 +364,14 @@ module Airbrake
|
|
364
364
|
# method: 'POST',
|
365
365
|
# route: '/thing/:id/create',
|
366
366
|
# status_code: 200,
|
367
|
-
# func: 'do_stuff',
|
368
|
-
# file: 'app/models/foo.rb',
|
369
|
-
# line: 452,
|
370
367
|
# timing: 123.45 # ms
|
371
368
|
# )
|
372
369
|
#
|
373
370
|
# @param [Hash{Symbol=>Object}] request_info
|
374
371
|
# @option request_info [String] :method The HTTP method that was invoked
|
375
372
|
# @option request_info [String] :route The route that was invoked
|
376
|
-
# @option request_info [Integer] :status_code The
|
373
|
+
# @option request_info [Integer] :status_code The response code that the
|
377
374
|
# route returned
|
378
|
-
# @option request_info [String] :func The function that called the query
|
379
|
-
# (optional)
|
380
|
-
# @option request_info [String] :file The file that has the function that
|
381
|
-
# called the query (optional)
|
382
|
-
# @option request_info [Integer] :line The line that executes the query
|
383
|
-
# (optional)
|
384
375
|
# @option request_info [Float] :timing How much time it took to process the
|
385
376
|
# request (in ms)
|
386
377
|
# @param [Hash] stash What needs to be appeneded to the stash, so it's
|
@@ -415,6 +406,9 @@ module Airbrake
|
|
415
406
|
# method: 'GET',
|
416
407
|
# route: '/things',
|
417
408
|
# query: 'SELECT * FROM things',
|
409
|
+
# func: 'do_stuff',
|
410
|
+
# file: 'app/models/foo.rb',
|
411
|
+
# line: 452,
|
418
412
|
# timing: 123.45 # ms
|
419
413
|
# )
|
420
414
|
#
|
@@ -424,6 +418,12 @@ module Airbrake
|
|
424
418
|
# @option query_info [String] :route The route that triggered this SQL
|
425
419
|
# query (optional)
|
426
420
|
# @option query_info [String] :query The query that was executed
|
421
|
+
# @option request_info [String] :func The function that called the query
|
422
|
+
# (optional)
|
423
|
+
# @option request_info [String] :file The file that has the function that
|
424
|
+
# called the query (optional)
|
425
|
+
# @option request_info [Integer] :line The line that executes the query
|
426
|
+
# (optional)
|
427
427
|
# @option query_info [Float] :timing How much time it took to process the
|
428
428
|
# query (in ms)
|
429
429
|
# @param [Hash] stash What needs to be appeneded to the stash, so it's
|
@@ -451,7 +451,7 @@ module Airbrake
|
|
451
451
|
# Increments performance breakdown statistics of a certain route.
|
452
452
|
#
|
453
453
|
# @example
|
454
|
-
# Airbrake.
|
454
|
+
# Airbrake.notify_performance_breakdown(
|
455
455
|
# method: 'POST',
|
456
456
|
# route: '/thing/:id/create',
|
457
457
|
# response_type: 'json',
|
@@ -523,24 +523,24 @@ module Airbrake
|
|
523
523
|
performance_notifier.notify_sync(queue)
|
524
524
|
end
|
525
525
|
|
526
|
-
# Runs a callback before {.notify_request}
|
527
|
-
# is useful if you want to
|
528
|
-
#
|
526
|
+
# Runs a callback before {.notify_request}, {.notify_query}, {.notify_queue}
|
527
|
+
# or {.notify_performance_breakdown} kicks in. This is useful if you want to
|
528
|
+
# ignore specific metrics or filter the data the metric contains.
|
529
529
|
#
|
530
|
-
# @example Ignore all
|
530
|
+
# @example Ignore all metrics
|
531
531
|
# Airbrake.add_performance_filter(&:ignore!)
|
532
532
|
# @example Filter sensitive data
|
533
|
-
# Airbrake.add_performance_filter do |
|
534
|
-
# case
|
533
|
+
# Airbrake.add_performance_filter do |metric|
|
534
|
+
# case metric
|
535
535
|
# when Airbrake::Query
|
536
|
-
#
|
536
|
+
# metric.route = '[Filtered]'
|
537
537
|
# when Airbrake::Request
|
538
|
-
#
|
538
|
+
# metric.query = '[Filtered]'
|
539
539
|
# end
|
540
540
|
# end
|
541
541
|
# @example Filter with help of a class
|
542
542
|
# class MyFilter
|
543
|
-
# def call(
|
543
|
+
# def call(metric)
|
544
544
|
# # ...
|
545
545
|
# end
|
546
546
|
# end
|
@@ -548,7 +548,7 @@ module Airbrake
|
|
548
548
|
# Airbrake.add_performance_filter(MyFilter.new)
|
549
549
|
#
|
550
550
|
# @param [#call] filter The filter object
|
551
|
-
# @yield [
|
551
|
+
# @yield [metric] The metric to filter
|
552
552
|
# @yieldparam [Airbrake::Query, Airbrake::Request]
|
553
553
|
# @yieldreturn [void]
|
554
554
|
# @return [void]
|
data/spec/config_spec.rb
CHANGED
@@ -127,22 +127,22 @@ RSpec.describe Airbrake::Config do
|
|
127
127
|
|
128
128
|
describe "#check_performance_options" do
|
129
129
|
it "returns a promise" do
|
130
|
-
|
131
|
-
expect(config.check_performance_options(
|
130
|
+
metric = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
|
131
|
+
expect(config.check_performance_options(metric))
|
132
132
|
.to be_an(Airbrake::Promise)
|
133
133
|
end
|
134
134
|
|
135
135
|
context "when performance stats are disabled" do
|
136
136
|
before { config.performance_stats = false }
|
137
137
|
|
138
|
-
let(:
|
138
|
+
let(:metric) do
|
139
139
|
Airbrake::Request.new(
|
140
140
|
method: 'GET', route: '/foo', status_code: 200, timing: 1,
|
141
141
|
)
|
142
142
|
end
|
143
143
|
|
144
144
|
it "returns a rejected promise" do
|
145
|
-
promise = config.check_performance_options(
|
145
|
+
promise = config.check_performance_options(metric)
|
146
146
|
expect(promise.value).to eq(
|
147
147
|
'error' => "The Performance Stats feature is disabled",
|
148
148
|
)
|
@@ -152,12 +152,12 @@ RSpec.describe Airbrake::Config do
|
|
152
152
|
context "when query stats are disabled" do
|
153
153
|
before { config.query_stats = false }
|
154
154
|
|
155
|
-
let(:
|
155
|
+
let(:metric) do
|
156
156
|
Airbrake::Query.new(method: 'GET', route: '/foo', query: '', timing: 1)
|
157
157
|
end
|
158
158
|
|
159
159
|
it "returns a rejected promise" do
|
160
|
-
promise = config.check_performance_options(
|
160
|
+
promise = config.check_performance_options(metric)
|
161
161
|
expect(promise.value).to eq(
|
162
162
|
'error' => "The Query Stats feature is disabled",
|
163
163
|
)
|
@@ -167,12 +167,12 @@ RSpec.describe Airbrake::Config do
|
|
167
167
|
context "when job stats are disabled" do
|
168
168
|
before { config.job_stats = false }
|
169
169
|
|
170
|
-
let(:
|
170
|
+
let(:metric) do
|
171
171
|
Airbrake::Queue.new(queue: 'foo_queue', error_count: 0, timing: 1)
|
172
172
|
end
|
173
173
|
|
174
174
|
it "returns a rejected promise" do
|
175
|
-
promise = config.check_performance_options(
|
175
|
+
promise = config.check_performance_options(metric)
|
176
176
|
expect(promise.value).to eq(
|
177
177
|
'error' => "The Job Stats feature is disabled",
|
178
178
|
)
|
@@ -522,8 +522,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
522
522
|
|
523
523
|
context "when a filter that modifies payload was defined" do
|
524
524
|
before do
|
525
|
-
perf_notifier.add_filter do |
|
526
|
-
|
525
|
+
perf_notifier.add_filter do |metric|
|
526
|
+
metric.route = '[Filtered]'
|
527
527
|
end
|
528
528
|
end
|
529
529
|
|
@@ -621,7 +621,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
|
|
621
621
|
describe "#delete_filter" do
|
622
622
|
let(:filter) do
|
623
623
|
Class.new do
|
624
|
-
def call(
|
624
|
+
def call(metric); end
|
625
625
|
end
|
626
626
|
end
|
627
627
|
|
data/spec/time_truncate_spec.rb
CHANGED
@@ -1,15 +1,30 @@
|
|
1
1
|
RSpec.describe Airbrake::TimeTruncate do
|
2
|
+
time = Time.new(2018, 1, 1, 0, 0, 20, 0)
|
3
|
+
time_with_zone = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
|
4
|
+
|
2
5
|
describe "#utc_truncate_minutes" do
|
3
|
-
|
4
|
-
time
|
5
|
-
|
6
|
-
|
6
|
+
shared_examples 'time conversion' do |t|
|
7
|
+
it "truncates the time to the floor minute and returns an RFC3339 timestamp" do
|
8
|
+
expect(described_class.utc_truncate_minutes(t))
|
9
|
+
.to eq('2018-01-01T00:00:00+00:00')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "converts time with zone to UTC" do
|
13
|
+
expect(described_class.utc_truncate_minutes(time_with_zone))
|
14
|
+
.to eq('2018-01-01T05:00:00+00:00')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when the time argument is a Time object" do
|
19
|
+
include_examples 'time conversion', time
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the time argument is a Float" do
|
23
|
+
include_examples 'time conversion', time.to_f
|
7
24
|
end
|
8
25
|
|
9
|
-
|
10
|
-
time
|
11
|
-
expect(described_class.utc_truncate_minutes(time))
|
12
|
-
.to eq('2018-01-01T05:00:00+00:00')
|
26
|
+
context "when the time argument is an Integer" do
|
27
|
+
include_examples 'time conversion', time.to_i
|
13
28
|
end
|
14
29
|
end
|
15
30
|
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: 6.0.
|
4
|
+
version: 6.0.2
|
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:
|
11
|
+
date: 2022-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbtree3
|
@@ -155,7 +155,8 @@ files:
|
|
155
155
|
homepage: https://airbrake.io
|
156
156
|
licenses:
|
157
157
|
- MIT
|
158
|
-
metadata:
|
158
|
+
metadata:
|
159
|
+
rubygems_mfa_required: 'true'
|
159
160
|
post_install_message:
|
160
161
|
rdoc_options: []
|
161
162
|
require_paths:
|