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,13 @@
|
|
1
|
+
RSpec.describe Airbrake::TimeTruncate do
|
2
|
+
describe "#utc_truncate_minutes" do
|
3
|
+
it "truncates time to the floor minute and returns an RFC3339 timestamp" do
|
4
|
+
time = Time.new(2018, 1, 1, 0, 0, 20, 0)
|
5
|
+
expect(subject.utc_truncate_minutes(time)).to eq('2018-01-01T00:00:00+00:00')
|
6
|
+
end
|
7
|
+
|
8
|
+
it "converts time with zone to UTC" do
|
9
|
+
time = Time.new(2018, 1, 1, 0, 0, 20, '-05:00')
|
10
|
+
expect(subject.utc_truncate_minutes(time)).to eq('2018-01-01T05:00:00+00:00')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/truncator_spec.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.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-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rbtree3
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.5.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.5.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +134,7 @@ files:
|
|
134
134
|
- lib/airbrake-ruby/code_hunk.rb
|
135
135
|
- lib/airbrake-ruby/config.rb
|
136
136
|
- lib/airbrake-ruby/config/validator.rb
|
137
|
+
- lib/airbrake-ruby/deploy_notifier.rb
|
137
138
|
- lib/airbrake-ruby/file_cache.rb
|
138
139
|
- lib/airbrake-ruby/filter_chain.rb
|
139
140
|
- lib/airbrake-ruby/filters/context_filter.rb
|
@@ -147,15 +148,21 @@ files:
|
|
147
148
|
- lib/airbrake-ruby/filters/keys_filter.rb
|
148
149
|
- lib/airbrake-ruby/filters/keys_whitelist.rb
|
149
150
|
- lib/airbrake-ruby/filters/root_directory_filter.rb
|
151
|
+
- lib/airbrake-ruby/filters/sql_filter.rb
|
150
152
|
- lib/airbrake-ruby/filters/system_exit_filter.rb
|
151
153
|
- lib/airbrake-ruby/filters/thread_filter.rb
|
154
|
+
- lib/airbrake-ruby/hash_keyable.rb
|
155
|
+
- lib/airbrake-ruby/ignorable.rb
|
152
156
|
- lib/airbrake-ruby/nested_exception.rb
|
153
157
|
- lib/airbrake-ruby/notice.rb
|
154
|
-
- lib/airbrake-ruby/
|
158
|
+
- lib/airbrake-ruby/notice_notifier.rb
|
159
|
+
- lib/airbrake-ruby/performance_notifier.rb
|
155
160
|
- lib/airbrake-ruby/promise.rb
|
156
161
|
- lib/airbrake-ruby/response.rb
|
157
|
-
- lib/airbrake-ruby/
|
162
|
+
- lib/airbrake-ruby/stat.rb
|
158
163
|
- lib/airbrake-ruby/sync_sender.rb
|
164
|
+
- lib/airbrake-ruby/tdigest.rb
|
165
|
+
- lib/airbrake-ruby/time_truncate.rb
|
159
166
|
- lib/airbrake-ruby/truncator.rb
|
160
167
|
- lib/airbrake-ruby/version.rb
|
161
168
|
- spec/airbrake_spec.rb
|
@@ -164,6 +171,7 @@ files:
|
|
164
171
|
- spec/code_hunk_spec.rb
|
165
172
|
- spec/config/validator_spec.rb
|
166
173
|
- spec/config_spec.rb
|
174
|
+
- spec/deploy_notifier_spec.rb
|
167
175
|
- spec/file_cache.rb
|
168
176
|
- spec/filter_chain_spec.rb
|
169
177
|
- spec/filters/context_filter_spec.rb
|
@@ -176,6 +184,7 @@ files:
|
|
176
184
|
- spec/filters/keys_blacklist_spec.rb
|
177
185
|
- spec/filters/keys_whitelist_spec.rb
|
178
186
|
- spec/filters/root_directory_filter_spec.rb
|
187
|
+
- spec/filters/sql_filter_spec.rb
|
179
188
|
- spec/filters/system_exit_filter_spec.rb
|
180
189
|
- spec/filters/thread_filter_spec.rb
|
181
190
|
- spec/fixtures/notroot.txt
|
@@ -185,15 +194,19 @@ files:
|
|
185
194
|
- spec/fixtures/project_root/short_file.rb
|
186
195
|
- spec/fixtures/project_root/vendor/bundle/ignored_file.rb
|
187
196
|
- spec/helpers.rb
|
197
|
+
- spec/ignorable_spec.rb
|
188
198
|
- spec/nested_exception_spec.rb
|
199
|
+
- spec/notice_notifier_spec.rb
|
200
|
+
- spec/notice_notifier_spec/options_spec.rb
|
189
201
|
- spec/notice_spec.rb
|
190
|
-
- spec/
|
191
|
-
- spec/notifier_spec/options_spec.rb
|
202
|
+
- spec/performance_notifier_spec.rb
|
192
203
|
- spec/promise_spec.rb
|
193
204
|
- spec/response_spec.rb
|
194
|
-
- spec/route_sender_spec.rb
|
195
205
|
- spec/spec_helper.rb
|
206
|
+
- spec/stat_spec.rb
|
196
207
|
- spec/sync_sender_spec.rb
|
208
|
+
- spec/tdigest_spec.rb
|
209
|
+
- spec/time_truncate_spec.rb
|
197
210
|
- spec/truncator_spec.rb
|
198
211
|
homepage: https://airbrake.io
|
199
212
|
licenses:
|
@@ -220,11 +233,11 @@ signing_key:
|
|
220
233
|
specification_version: 4
|
221
234
|
summary: Ruby notifier for https://airbrake.io
|
222
235
|
test_files:
|
223
|
-
- spec/route_sender_spec.rb
|
224
236
|
- spec/truncator_spec.rb
|
225
237
|
- spec/helpers.rb
|
226
238
|
- spec/filters/exception_attributes_filter_spec.rb
|
227
239
|
- spec/filters/root_directory_filter_spec.rb
|
240
|
+
- spec/filters/sql_filter_spec.rb
|
228
241
|
- spec/filters/keys_whitelist_spec.rb
|
229
242
|
- spec/filters/system_exit_filter_spec.rb
|
230
243
|
- spec/filters/thread_filter_spec.rb
|
@@ -238,13 +251,19 @@ test_files:
|
|
238
251
|
- spec/spec_helper.rb
|
239
252
|
- spec/notice_spec.rb
|
240
253
|
- spec/config_spec.rb
|
254
|
+
- spec/tdigest_spec.rb
|
241
255
|
- spec/async_sender_spec.rb
|
256
|
+
- spec/stat_spec.rb
|
242
257
|
- spec/backtrace_spec.rb
|
258
|
+
- spec/notice_notifier_spec.rb
|
259
|
+
- spec/time_truncate_spec.rb
|
243
260
|
- spec/promise_spec.rb
|
244
261
|
- spec/config/validator_spec.rb
|
245
262
|
- spec/sync_sender_spec.rb
|
263
|
+
- spec/ignorable_spec.rb
|
264
|
+
- spec/deploy_notifier_spec.rb
|
265
|
+
- spec/performance_notifier_spec.rb
|
246
266
|
- spec/airbrake_spec.rb
|
247
|
-
- spec/notifier_spec.rb
|
248
267
|
- spec/nested_exception_spec.rb
|
249
268
|
- spec/filter_chain_spec.rb
|
250
269
|
- spec/response_spec.rb
|
@@ -256,4 +275,4 @@ test_files:
|
|
256
275
|
- spec/fixtures/project_root/code.rb
|
257
276
|
- spec/fixtures/project_root/short_file.rb
|
258
277
|
- spec/fixtures/project_root/vendor/bundle/ignored_file.rb
|
259
|
-
- spec/
|
278
|
+
- spec/notice_notifier_spec/options_spec.rb
|
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'tdigest'
|
2
|
-
require 'base64'
|
3
|
-
|
4
|
-
module Airbrake
|
5
|
-
# RouteSender aggregates information about requests and periodically sends
|
6
|
-
# collected data to Airbrake.
|
7
|
-
# @since v3.0.0
|
8
|
-
class RouteSender
|
9
|
-
# Monkey-patch https://github.com/castle/tdigest to pack with Big Endian
|
10
|
-
# (instead of Little Endian) since our backend wants it.
|
11
|
-
#
|
12
|
-
# @see https://github.com/castle/tdigest/blob/master/lib/tdigest/tdigest.rb
|
13
|
-
# @since v3.0.0
|
14
|
-
# @api private
|
15
|
-
module TDigestBigEndianness
|
16
|
-
refine TDigest::TDigest do
|
17
|
-
# rubocop:disable Metrics/AbcSize
|
18
|
-
def as_small_bytes
|
19
|
-
size = @centroids.size
|
20
|
-
output = [self.class::SMALL_ENCODING, compression, size]
|
21
|
-
x = 0
|
22
|
-
# delta encoding allows saving 4-bytes floats
|
23
|
-
mean_arr = @centroids.map do |_, c|
|
24
|
-
val = c.mean - x
|
25
|
-
x = c.mean
|
26
|
-
val
|
27
|
-
end
|
28
|
-
output += mean_arr
|
29
|
-
# Variable length encoding of numbers
|
30
|
-
c_arr = @centroids.each_with_object([]) do |(_, c), arr|
|
31
|
-
k = 0
|
32
|
-
n = c.n
|
33
|
-
while n < 0 || n > 0x7f
|
34
|
-
b = 0x80 | (0x7f & n)
|
35
|
-
arr << b
|
36
|
-
n = n >> 7
|
37
|
-
k += 1
|
38
|
-
raise 'Unreasonable large number' if k > 6
|
39
|
-
end
|
40
|
-
arr << n
|
41
|
-
end
|
42
|
-
output += c_arr
|
43
|
-
output.pack("NGNg#{size}C#{size}")
|
44
|
-
end
|
45
|
-
# rubocop:enable Metrics/AbcSize
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
using TDigestBigEndianness
|
50
|
-
|
51
|
-
# The key that represents a route.
|
52
|
-
RouteKey = Struct.new(:method, :route, :statusCode, :time)
|
53
|
-
|
54
|
-
# RouteStat holds data that describes a route's performance.
|
55
|
-
RouteStat = Struct.new(:count, :sum, :sumsq, :tdigest) do
|
56
|
-
# @param [Integer] count The number of requests
|
57
|
-
# @param [Float] sum The sum of request duration in milliseconds
|
58
|
-
# @param [Float] sumsq The squared sum of request duration in milliseconds
|
59
|
-
# @param [TDigest::TDigest] tdigest By default, the compression is 20
|
60
|
-
def initialize(
|
61
|
-
count: 0, sum: 0.0, sumsq: 0.0, tdigest: TDigest::TDigest.new(0.05)
|
62
|
-
)
|
63
|
-
super(count, sum, sumsq, tdigest)
|
64
|
-
end
|
65
|
-
|
66
|
-
# @return [Hash{String=>Object}] the route stat as a hash with compressed
|
67
|
-
# and serialized as binary base64 tdigest
|
68
|
-
def to_h
|
69
|
-
tdigest.compress!
|
70
|
-
{
|
71
|
-
'count' => count,
|
72
|
-
'sum' => sum,
|
73
|
-
'sumsq' => sumsq,
|
74
|
-
'tdigest' => Base64.strict_encode64(tdigest.as_small_bytes)
|
75
|
-
}
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param [Airbrake::Config] config
|
80
|
-
def initialize(config)
|
81
|
-
@config = config
|
82
|
-
@flush_period = config.route_stats_flush_period
|
83
|
-
@sender = SyncSender.new(config, :put)
|
84
|
-
@routes = {}
|
85
|
-
@thread = nil
|
86
|
-
@mutex = Mutex.new
|
87
|
-
end
|
88
|
-
|
89
|
-
# @macro see_public_api_method
|
90
|
-
# @param [Airbrake::Promise] promise
|
91
|
-
def notify_request(request_info, promise = Airbrake::Promise.new)
|
92
|
-
route = create_route_key(
|
93
|
-
request_info[:method],
|
94
|
-
request_info[:route],
|
95
|
-
request_info[:status_code],
|
96
|
-
utc_truncate_minutes(request_info[:start_time])
|
97
|
-
)
|
98
|
-
|
99
|
-
@mutex.synchronize do
|
100
|
-
@routes[route] ||= RouteStat.new
|
101
|
-
increment_stats(request_info, @routes[route])
|
102
|
-
|
103
|
-
if @flush_period > 0
|
104
|
-
schedule_flush(promise)
|
105
|
-
else
|
106
|
-
send(@routes, promise)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
promise
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
def create_route_key(method, route, status_code, tm)
|
116
|
-
# rubocop:disable Style/DateTime
|
117
|
-
time = DateTime.new(
|
118
|
-
tm.year, tm.month, tm.day, tm.hour, tm.min, 0, tm.zone || 0
|
119
|
-
)
|
120
|
-
# rubocop:enable Style/DateTime
|
121
|
-
RouteKey.new(method, route, status_code, time.rfc3339)
|
122
|
-
end
|
123
|
-
|
124
|
-
def increment_stats(request_info, stat)
|
125
|
-
stat.count += 1
|
126
|
-
|
127
|
-
end_time = request_info[:end_time] || Time.new
|
128
|
-
ms = (end_time - request_info[:start_time]) * 1000
|
129
|
-
|
130
|
-
stat.sum += ms
|
131
|
-
stat.sumsq += ms * ms
|
132
|
-
|
133
|
-
stat.tdigest.push(ms)
|
134
|
-
end
|
135
|
-
|
136
|
-
def schedule_flush(promise)
|
137
|
-
@thread ||= Thread.new do
|
138
|
-
sleep(@flush_period)
|
139
|
-
|
140
|
-
routes = nil
|
141
|
-
@mutex.synchronize do
|
142
|
-
routes = @routes
|
143
|
-
@routes = {}
|
144
|
-
@thread = nil
|
145
|
-
end
|
146
|
-
|
147
|
-
send(routes, promise)
|
148
|
-
end
|
149
|
-
|
150
|
-
# Setting a name is needed to test the timer.
|
151
|
-
# Ruby <=2.2 doesn't support Thread#name, so we have this check.
|
152
|
-
@thread.name = 'route-stat-thread' if @thread.respond_to?(:name)
|
153
|
-
end
|
154
|
-
|
155
|
-
def send(routes, promise)
|
156
|
-
if routes.none?
|
157
|
-
raise "#{self.class.name}##{__method__}: routes cannot be empty. Race?"
|
158
|
-
end
|
159
|
-
|
160
|
-
@config.logger.debug("#{LOG_LABEL} RouteStats#send: #{routes}")
|
161
|
-
|
162
|
-
@sender.send(
|
163
|
-
{ routes: routes.map { |k, v| k.to_h.merge(v.to_h) } },
|
164
|
-
promise,
|
165
|
-
URI.join(@config.host, "api/v5/projects/#{@config.project_id}/routes-stats")
|
166
|
-
)
|
167
|
-
end
|
168
|
-
|
169
|
-
def utc_truncate_minutes(time)
|
170
|
-
time_array = time.to_a
|
171
|
-
time_array[0] = 0
|
172
|
-
Time.utc(*time_array)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
data/spec/route_sender_spec.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe Airbrake::RouteSender do
|
4
|
-
let(:endpoint) { 'https://api.airbrake.io/api/v5/projects/1/routes-stats' }
|
5
|
-
|
6
|
-
let(:config) do
|
7
|
-
Airbrake::Config.new(
|
8
|
-
project_id: 1,
|
9
|
-
project_key: 'banana',
|
10
|
-
route_stats_flush_period: 0.1
|
11
|
-
)
|
12
|
-
end
|
13
|
-
|
14
|
-
subject { described_class.new(config) }
|
15
|
-
|
16
|
-
describe "#notify_request" do
|
17
|
-
before do
|
18
|
-
stub_request(:put, endpoint).to_return(status: 200, body: '')
|
19
|
-
end
|
20
|
-
|
21
|
-
# Let the request finish.
|
22
|
-
after { sleep 0.2 }
|
23
|
-
|
24
|
-
it "rounds time to the floor minute" do
|
25
|
-
subject.notify_request(
|
26
|
-
method: 'GET',
|
27
|
-
route: '/foo',
|
28
|
-
status_code: 200,
|
29
|
-
start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
|
30
|
-
)
|
31
|
-
sleep 0.2
|
32
|
-
expect(
|
33
|
-
a_request(:put, endpoint).with(body: /"time":"2018-01-01T00:00:00\+00:00"/)
|
34
|
-
).to have_been_made
|
35
|
-
end
|
36
|
-
|
37
|
-
it "increments routes with the same key" do
|
38
|
-
subject.notify_request(
|
39
|
-
method: 'GET',
|
40
|
-
route: '/foo',
|
41
|
-
status_code: 200,
|
42
|
-
start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
|
43
|
-
)
|
44
|
-
subject.notify_request(
|
45
|
-
method: 'GET',
|
46
|
-
route: '/foo',
|
47
|
-
status_code: 200,
|
48
|
-
start_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
|
49
|
-
)
|
50
|
-
sleep 0.2
|
51
|
-
expect(
|
52
|
-
a_request(:put, endpoint).with(body: /"count":2/)
|
53
|
-
).to have_been_made
|
54
|
-
end
|
55
|
-
|
56
|
-
it "groups routes by time" do
|
57
|
-
subject.notify_request(
|
58
|
-
method: 'GET',
|
59
|
-
route: '/foo',
|
60
|
-
status_code: 200,
|
61
|
-
start_time: Time.new(2018, 1, 1, 0, 0, 49, 0),
|
62
|
-
end_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
|
63
|
-
)
|
64
|
-
subject.notify_request(
|
65
|
-
method: 'GET',
|
66
|
-
route: '/foo',
|
67
|
-
status_code: 200,
|
68
|
-
start_time: Time.new(2018, 1, 1, 0, 1, 49, 0),
|
69
|
-
end_time: Time.new(2018, 1, 1, 0, 1, 55, 0)
|
70
|
-
)
|
71
|
-
sleep 0.2
|
72
|
-
expect(
|
73
|
-
a_request(:put, endpoint).with(
|
74
|
-
body: %r|\A
|
75
|
-
{"routes":\[
|
76
|
-
{"method":"GET","route":"/foo","statusCode":200,
|
77
|
-
"time":"2018-01-01T00:00:00\+00:00","count":1,"sum":1000.0,
|
78
|
-
"sumsq":1000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUR6AAAB"},
|
79
|
-
{"method":"GET","route":"/foo","statusCode":200,
|
80
|
-
"time":"2018-01-01T00:01:00\+00:00","count":1,"sum":6000.0,
|
81
|
-
"sumsq":36000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUW7gAAB"}\]}
|
82
|
-
\z|x
|
83
|
-
)
|
84
|
-
).to have_been_made
|
85
|
-
end
|
86
|
-
|
87
|
-
it "groups routes by route key" do
|
88
|
-
subject.notify_request(
|
89
|
-
method: 'GET',
|
90
|
-
route: '/foo',
|
91
|
-
status_code: 200,
|
92
|
-
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
|
93
|
-
end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
|
94
|
-
)
|
95
|
-
subject.notify_request(
|
96
|
-
method: 'POST',
|
97
|
-
route: '/foo',
|
98
|
-
status_code: 200,
|
99
|
-
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
|
100
|
-
end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
|
101
|
-
)
|
102
|
-
sleep 0.2
|
103
|
-
expect(
|
104
|
-
a_request(:put, endpoint).with(
|
105
|
-
body: %r|\A
|
106
|
-
{"routes":\[
|
107
|
-
{"method":"GET","route":"/foo","statusCode":200,
|
108
|
-
"time":"2018-01-01T00:49:00\+00:00","count":1,"sum":60000.0,
|
109
|
-
"sumsq":3600000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB"},
|
110
|
-
{"method":"POST","route":"/foo","statusCode":200,
|
111
|
-
"time":"2018-01-01T00:49:00\+00:00","count":1,"sum":60000.0,
|
112
|
-
"sumsq":3600000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB"}\]}
|
113
|
-
\z|x
|
114
|
-
)
|
115
|
-
).to have_been_made
|
116
|
-
end
|
117
|
-
|
118
|
-
it "returns a promise" do
|
119
|
-
promise = subject.notify_request(
|
120
|
-
method: 'GET',
|
121
|
-
route: '/foo',
|
122
|
-
status_code: 200,
|
123
|
-
start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
|
124
|
-
)
|
125
|
-
sleep 0.2
|
126
|
-
expect(promise).to be_an(Airbrake::Promise)
|
127
|
-
expect(promise.value).to eq('' => nil)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|