airbrake-ruby 2.13.0.pre.1 → 3.0.0.rc.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.rb +1 -5
- data/lib/airbrake-ruby/backtrace.rb +1 -16
- data/lib/airbrake-ruby/config.rb +1 -1
- data/lib/airbrake-ruby/filter_chain.rb +56 -1
- data/lib/airbrake-ruby/notifier.rb +30 -39
- data/lib/airbrake-ruby/response.rb +1 -1
- data/lib/airbrake-ruby/route_sender.rb +63 -8
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/backtrace_spec.rb +5 -25
- data/spec/filter_chain_spec.rb +5 -1
- data/spec/notifier_spec.rb +30 -0
- data/spec/response_spec.rb +1 -1
- data/spec/route_sender_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -0
- metadata +22 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0aef633a546613b3d46a1669505df654fcc4348b
|
4
|
+
data.tar.gz: c35b98d3ffa46c7ee3fe976546585f27ca6d1bd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 820453ab4d27d72c7f356958af555bc361507ca48cde546e6bc15f77cb32077c2cc1623d6a0afe882c37b9ade81888b58ddaadbd2c7f17b820a6011ab666877d
|
7
|
+
data.tar.gz: fc7078da83d4cd3d2e4e4c2602e5441e9ebd6751410cfdf8ffb6c4998f1832790a3ccfb41aa97a39470315b60a965b0b91059bc4914c366f923e986842f8adf1
|
data/lib/airbrake-ruby.rb
CHANGED
@@ -76,10 +76,6 @@ module Airbrake
|
|
76
76
|
# @return [String] the label to be prepended to the log output
|
77
77
|
LOG_LABEL = '**Airbrake:'.freeze
|
78
78
|
|
79
|
-
# @return [Boolean] true if current Ruby is Ruby 2.0.*. The result is used
|
80
|
-
# for special cases where we need to work around older implementations
|
81
|
-
RUBY_20 = RUBY_VERSION.start_with?('2.0')
|
82
|
-
|
83
79
|
# @return [Boolean] true if current Ruby is JRuby. The result is used for
|
84
80
|
# special cases where we need to work around older implementations
|
85
81
|
JRUBY = (RUBY_ENGINE == 'jruby')
|
@@ -366,7 +362,7 @@ module Airbrake
|
|
366
362
|
# milliseconds
|
367
363
|
# @param [Time] time When the request happened
|
368
364
|
# @return [void]
|
369
|
-
# @since
|
365
|
+
# @since v3.0.0
|
370
366
|
def inc_request(method, route, status_code, dur, time)
|
371
367
|
@notifiers[:default].inc_request(method, route, status_code, dur, time)
|
372
368
|
end
|
@@ -83,10 +83,6 @@ module Airbrake
|
|
83
83
|
#{RUBY}
|
84
84
|
)
|
85
85
|
\z/x
|
86
|
-
|
87
|
-
# @return [Regexp] +EXECJS+ pattern without named captures and
|
88
|
-
# uncommon frames
|
89
|
-
EXECJS_SIMPLIFIED = /\A.+ \(.+:\d+:\d+\)\z/
|
90
86
|
end
|
91
87
|
|
92
88
|
# @return [Integer] how many first frames should include code hunks
|
@@ -136,24 +132,13 @@ module Airbrake
|
|
136
132
|
defined?(OCIError) && exception.is_a?(OCIError)
|
137
133
|
end
|
138
134
|
|
139
|
-
# rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
140
135
|
def execjs_exception?(exception)
|
141
136
|
return false unless defined?(ExecJS::RuntimeError)
|
142
137
|
return true if exception.is_a?(ExecJS::RuntimeError)
|
143
|
-
|
144
|
-
if Airbrake::RUBY_20
|
145
|
-
# Ruby <2.1 doesn't support Exception#cause. We work around this by
|
146
|
-
# parsing backtraces. It's slow, so we check only a few first frames.
|
147
|
-
exception.backtrace[0..2].each do |frame|
|
148
|
-
return true if frame =~ Patterns::EXECJS_SIMPLIFIED
|
149
|
-
end
|
150
|
-
elsif exception.cause && exception.cause.is_a?(ExecJS::RuntimeError)
|
151
|
-
return true
|
152
|
-
end
|
138
|
+
return true if exception.cause && exception.cause.is_a?(ExecJS::RuntimeError)
|
153
139
|
|
154
140
|
false
|
155
141
|
end
|
156
|
-
# rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
157
142
|
|
158
143
|
def stack_frame(config, regexp, stackframe)
|
159
144
|
if (match = match_frame(regexp, stackframe))
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -86,7 +86,7 @@ module Airbrake
|
|
86
86
|
# @return [Integer] how many seconds to wait before sending collected route
|
87
87
|
# stats
|
88
88
|
# @api public
|
89
|
-
# @since
|
89
|
+
# @since v3.0.0
|
90
90
|
attr_accessor :route_stats_flush_period
|
91
91
|
|
92
92
|
# @param [Hash{Symbol=>Object}] user_config the hash to be used to build the
|
@@ -18,9 +18,12 @@ module Airbrake
|
|
18
18
|
# @return [Integer]
|
19
19
|
DEFAULT_WEIGHT = 0
|
20
20
|
|
21
|
-
def initialize
|
21
|
+
def initialize(config, context)
|
22
|
+
@config = config
|
23
|
+
@context = context
|
22
24
|
@filters = []
|
23
25
|
DEFAULT_FILTERS.each { |f| add_filter(f.new) }
|
26
|
+
add_default_filters
|
24
27
|
end
|
25
28
|
|
26
29
|
# Adds a filter to the filter chain. Sorts filters by weight.
|
@@ -44,5 +47,57 @@ module Airbrake
|
|
44
47
|
filter.call(notice)
|
45
48
|
end
|
46
49
|
end
|
50
|
+
|
51
|
+
# @return [String] customized inspect to lessen the amount of clutter
|
52
|
+
def inspect
|
53
|
+
@filters.map(&:class)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [String] {#inspect} for PrettyPrint
|
57
|
+
def pretty_print(q)
|
58
|
+
q.text('[')
|
59
|
+
|
60
|
+
# Make nesting of the first element consistent on JRuby and MRI.
|
61
|
+
q.nest(2) { q.breakable }
|
62
|
+
|
63
|
+
q.nest(2) do
|
64
|
+
q.seplist(@filters) { |f| q.pp(f.class) }
|
65
|
+
end
|
66
|
+
q.text(']')
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# rubocop:disable Metrics/AbcSize
|
72
|
+
def add_default_filters
|
73
|
+
if (whitelist_keys = @config.whitelist_keys).any?
|
74
|
+
add_filter(
|
75
|
+
Airbrake::Filters::KeysWhitelist.new(@config.logger, whitelist_keys)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
if (blacklist_keys = @config.blacklist_keys).any?
|
80
|
+
add_filter(
|
81
|
+
Airbrake::Filters::KeysBlacklist.new(@config.logger, blacklist_keys)
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
add_filter(Airbrake::Filters::ContextFilter.new(@context))
|
86
|
+
add_filter(Airbrake::Filters::ExceptionAttributesFilter.new(@config.logger))
|
87
|
+
|
88
|
+
return unless (root_directory = @config.root_directory)
|
89
|
+
[
|
90
|
+
Airbrake::Filters::RootDirectoryFilter,
|
91
|
+
Airbrake::Filters::GitRevisionFilter,
|
92
|
+
Airbrake::Filters::GitRepositoryFilter
|
93
|
+
].each do |filter|
|
94
|
+
add_filter(filter.new(root_directory))
|
95
|
+
end
|
96
|
+
|
97
|
+
add_filter(
|
98
|
+
Airbrake::Filters::GitLastCheckoutFilter.new(@config.logger, root_directory)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
# rubocop:enable Metrics/AbcSize
|
47
102
|
end
|
48
103
|
end
|
@@ -9,6 +9,12 @@ module Airbrake
|
|
9
9
|
# @return [String] the label to be prepended to the log output
|
10
10
|
LOG_LABEL = '**Airbrake:'.freeze
|
11
11
|
|
12
|
+
# @return [String] inspect output template
|
13
|
+
INSPECT_TEMPLATE =
|
14
|
+
"#<#{self}:0x%<id>s project_id=\"%<project_id>s\" " \
|
15
|
+
"project_key=\"%<project_key>s\" " \
|
16
|
+
"host=\"%<host>s\" filter_chain=%<filter_chain>s>".freeze
|
17
|
+
|
12
18
|
# Creates a new Airbrake notifier with the given config options.
|
13
19
|
#
|
14
20
|
# @example Configuring with a Hash
|
@@ -30,13 +36,9 @@ module Airbrake
|
|
30
36
|
raise Airbrake::Error, @config.validation_error_message unless @config.valid?
|
31
37
|
|
32
38
|
@context = {}
|
33
|
-
|
34
|
-
@filter_chain = FilterChain.new
|
35
|
-
add_default_filters
|
36
|
-
|
39
|
+
@filter_chain = FilterChain.new(@config, @context)
|
37
40
|
@async_sender = AsyncSender.new(@config)
|
38
41
|
@sync_sender = SyncSender.new(@config)
|
39
|
-
|
40
42
|
@route_sender = RouteSender.new(@config)
|
41
43
|
end
|
42
44
|
|
@@ -102,6 +104,29 @@ module Airbrake
|
|
102
104
|
@route_sender.inc_request(*args)
|
103
105
|
end
|
104
106
|
|
107
|
+
# @return [String] customized inspect to lessen the amount of clutter
|
108
|
+
def inspect
|
109
|
+
format(
|
110
|
+
INSPECT_TEMPLATE,
|
111
|
+
id: (object_id << 1).to_s(16).rjust(16, '0'),
|
112
|
+
project_id: @config.project_id,
|
113
|
+
project_key: @config.project_key,
|
114
|
+
host: @config.host,
|
115
|
+
filter_chain: @filter_chain.inspect
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [String] {#inspect} for PrettyPrint
|
120
|
+
def pretty_print(q)
|
121
|
+
q.text("#<#{self.class}:0x#{(object_id << 1).to_s(16).rjust(16, '0')} ")
|
122
|
+
q.text(
|
123
|
+
"project_id=\"#{@config.project_id}\" project_key=\"#{@config.project_key}\" " \
|
124
|
+
"host=\"#{@config.host}\" filter_chain="
|
125
|
+
)
|
126
|
+
q.pp(@filter_chain)
|
127
|
+
q.text('>')
|
128
|
+
end
|
129
|
+
|
105
130
|
private
|
106
131
|
|
107
132
|
def convert_to_exception(ex)
|
@@ -152,39 +177,5 @@ module Airbrake
|
|
152
177
|
return caller_copy if clean_bt.empty?
|
153
178
|
clean_bt
|
154
179
|
end
|
155
|
-
|
156
|
-
# rubocop:disable Metrics/AbcSize
|
157
|
-
def add_default_filters
|
158
|
-
if (whitelist_keys = @config.whitelist_keys).any?
|
159
|
-
@filter_chain.add_filter(
|
160
|
-
Airbrake::Filters::KeysWhitelist.new(@config.logger, whitelist_keys)
|
161
|
-
)
|
162
|
-
end
|
163
|
-
|
164
|
-
if (blacklist_keys = @config.blacklist_keys).any?
|
165
|
-
@filter_chain.add_filter(
|
166
|
-
Airbrake::Filters::KeysBlacklist.new(@config.logger, blacklist_keys)
|
167
|
-
)
|
168
|
-
end
|
169
|
-
|
170
|
-
@filter_chain.add_filter(Airbrake::Filters::ContextFilter.new(@context))
|
171
|
-
@filter_chain.add_filter(
|
172
|
-
Airbrake::Filters::ExceptionAttributesFilter.new(@config.logger)
|
173
|
-
)
|
174
|
-
|
175
|
-
return unless (root_directory = @config.root_directory)
|
176
|
-
[
|
177
|
-
Airbrake::Filters::RootDirectoryFilter,
|
178
|
-
Airbrake::Filters::GitRevisionFilter,
|
179
|
-
Airbrake::Filters::GitRepositoryFilter
|
180
|
-
].each do |filter|
|
181
|
-
@filter_chain.add_filter(filter.new(root_directory))
|
182
|
-
end
|
183
|
-
|
184
|
-
@filter_chain.add_filter(
|
185
|
-
Airbrake::Filters::GitLastCheckoutFilter.new(@config.logger, root_directory)
|
186
|
-
)
|
187
|
-
end
|
188
|
-
# rubocop:enable Metrics/AbcSize
|
189
180
|
end
|
190
181
|
end
|
@@ -1,20 +1,76 @@
|
|
1
|
+
require 'tdigest'
|
2
|
+
require 'base64'
|
3
|
+
|
1
4
|
module Airbrake
|
2
5
|
# RouteSender aggregates information about requests and periodically sends
|
3
6
|
# collected data to Airbrake.
|
4
|
-
# @since
|
7
|
+
# @since v3.0.0
|
5
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
|
+
|
6
51
|
# The key that represents a route.
|
7
52
|
RouteKey = Struct.new(:method, :route, :statusCode, :time)
|
8
53
|
|
9
54
|
# RouteStat holds data that describes a route's performance.
|
10
|
-
RouteStat = Struct.new(:count, :sum, :sumsq, :
|
55
|
+
RouteStat = Struct.new(:count, :sum, :sumsq, :tdigest) do
|
11
56
|
# @param [Integer] count The number of requests
|
12
57
|
# @param [Float] sum The sum of request duration in milliseconds
|
13
58
|
# @param [Float] sumsq The squared sum of request duration in milliseconds
|
14
|
-
# @param [
|
15
|
-
|
16
|
-
|
17
|
-
|
59
|
+
# @param [TDigest::TDigest] tdigest
|
60
|
+
def initialize(count: 0, sum: 0.0, sumsq: 0.0, tdigest: TDigest::TDigest.new)
|
61
|
+
super(count, sum, sumsq, tdigest)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Hash{String=>Object}] the route stat as a hash with compressed
|
65
|
+
# and serialized as binary base64 tdigest
|
66
|
+
def to_h
|
67
|
+
tdigest.compress!
|
68
|
+
{
|
69
|
+
'count' => count,
|
70
|
+
'sum' => sum,
|
71
|
+
'sumsq' => sumsq,
|
72
|
+
'tDigest' => Base64.strict_encode64(tdigest.as_small_bytes)
|
73
|
+
}
|
18
74
|
end
|
19
75
|
end
|
20
76
|
|
@@ -66,8 +122,7 @@ module Airbrake
|
|
66
122
|
stat.sum += ms
|
67
123
|
stat.sumsq += ms * ms
|
68
124
|
|
69
|
-
stat.
|
70
|
-
stat.max = ms if ms > stat.max
|
125
|
+
stat.tdigest.push(ms)
|
71
126
|
end
|
72
127
|
|
73
128
|
def schedule_flush(promise)
|
data/spec/backtrace_spec.rb
CHANGED
@@ -248,6 +248,8 @@ RSpec.describe Airbrake::Backtrace do
|
|
248
248
|
"/opt/rubies/ruby-2.3.1/lib/ruby/2.3.0/benchmark.rb:308:in `realtime'"]
|
249
249
|
end
|
250
250
|
|
251
|
+
let(:ex) { ExecJS::RuntimeError.new.tap { |e| e.set_backtrace(bt) } }
|
252
|
+
|
251
253
|
let(:parsed_backtrace) do
|
252
254
|
[{ file: '(execjs)', line: 6692, function: 'compile' },
|
253
255
|
{ file: '<anonymous>', line: 1, function: 'eval' },
|
@@ -261,31 +263,9 @@ RSpec.describe Airbrake::Backtrace do
|
|
261
263
|
function: 'realtime' }]
|
262
264
|
end
|
263
265
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
it "returns a properly formatted array of hashes" do
|
268
|
-
stub_const('ExecJS::RuntimeError', AirbrakeTestError)
|
269
|
-
stub_const('Airbrake::RUBY_20', false)
|
270
|
-
|
271
|
-
expect(described_class.parse(config, ex)).to eq(parsed_backtrace)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context "when on Ruby 2.0" do
|
276
|
-
context "and when exception's class isn't ExecJS" do
|
277
|
-
let(:ex) do
|
278
|
-
ActionView::Template::Error.new.tap { |e| e.set_backtrace(bt) }
|
279
|
-
end
|
280
|
-
|
281
|
-
it "returns a properly formatted array of hashes" do
|
282
|
-
stub_const('ActionView::Template::Error', AirbrakeTestError)
|
283
|
-
stub_const('ExecJS::RuntimeError', NameError)
|
284
|
-
stub_const('Airbrake::RUBY_20', true)
|
285
|
-
|
286
|
-
expect(described_class.parse(config, ex)).to eq(parsed_backtrace)
|
287
|
-
end
|
288
|
-
end
|
266
|
+
it "returns a properly formatted array of hashes" do
|
267
|
+
stub_const('ExecJS::RuntimeError', AirbrakeTestError)
|
268
|
+
expect(described_class.parse(config, ex)).to eq(parsed_backtrace)
|
289
269
|
end
|
290
270
|
end
|
291
271
|
|
data/spec/filter_chain_spec.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Airbrake::FilterChain do
|
4
|
+
subject { described_class.new(config, {}) }
|
5
|
+
|
6
|
+
let(:config) { Airbrake::Config.new }
|
7
|
+
|
4
8
|
let(:notice) do
|
5
|
-
Airbrake::Notice.new(
|
9
|
+
Airbrake::Notice.new(config, AirbrakeTestError.new)
|
6
10
|
end
|
7
11
|
|
8
12
|
describe "#refine" do
|
data/spec/notifier_spec.rb
CHANGED
@@ -459,5 +459,35 @@ RSpec.describe Airbrake::Notifier do
|
|
459
459
|
subject.inc_request('GET', '/foo', 200, 1000, t)
|
460
460
|
end
|
461
461
|
end
|
462
|
+
|
463
|
+
describe "#inspect" do
|
464
|
+
it "displays object information" do
|
465
|
+
expect(subject.inspect).to match(/
|
466
|
+
#<Airbrake::Notifier:0x\w+\s
|
467
|
+
project_id="\d+"\s
|
468
|
+
project_key=".+"\s
|
469
|
+
host="http.+"\s
|
470
|
+
filter_chain=\[.+\]>
|
471
|
+
/x)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
describe "#pretty_print" do
|
476
|
+
it "displays object information in a beautiful way" do
|
477
|
+
q = PP.new
|
478
|
+
|
479
|
+
# Guarding is needed to fix JRuby failure:
|
480
|
+
# NoMethodError: undefined method `[]' for nil:NilClass
|
481
|
+
q.guard_inspect_key { subject.pretty_print(q) }
|
482
|
+
|
483
|
+
expect(q.output).to match(/
|
484
|
+
#<Airbrake::Notifier:0x\w+\s
|
485
|
+
project_id="\d+"\s
|
486
|
+
project_key=".+"\s
|
487
|
+
host="http.+"\s
|
488
|
+
filter_chain=\[\n\s\s
|
489
|
+
/x)
|
490
|
+
end
|
491
|
+
end
|
462
492
|
end
|
463
493
|
# rubocop:enable Layout/DotPosition
|
data/spec/response_spec.rb
CHANGED
@@ -5,7 +5,7 @@ RSpec.describe Airbrake::Response do
|
|
5
5
|
let(:out) { StringIO.new }
|
6
6
|
let(:logger) { Logger.new(out) }
|
7
7
|
|
8
|
-
[200, 201].each do |code|
|
8
|
+
[200, 201, 204].each do |code|
|
9
9
|
context "when response code is #{code}" do
|
10
10
|
it "logs response body" do
|
11
11
|
described_class.parse(OpenStruct.new(code: code, body: '{}'), logger)
|
data/spec/route_sender_spec.rb
CHANGED
@@ -48,10 +48,10 @@ RSpec.describe Airbrake::RouteSender do
|
|
48
48
|
{"routes":\[
|
49
49
|
{"method":"GET","route":"/foo","statusCode":200,
|
50
50
|
"time":"2018-01-01T00:00:00\+00:00","count":1,"sum":24.0,
|
51
|
-
"sumsq":576.0,"
|
51
|
+
"sumsq":576.0,"tDigest":"AAAAAkBZAAAAAAAAAAAAAUHAAAAB"},
|
52
52
|
{"method":"GET","route":"/foo","statusCode":200,
|
53
53
|
"time":"2018-01-01T00:01:00\+00:00","count":1,"sum":10.0,
|
54
|
-
"sumsq":100.0,"
|
54
|
+
"sumsq":100.0,"tDigest":"AAAAAkBZAAAAAAAAAAAAAUEgAAAB"}\]}
|
55
55
|
\z|x
|
56
56
|
)
|
57
57
|
).to have_been_made
|
@@ -67,10 +67,10 @@ RSpec.describe Airbrake::RouteSender do
|
|
67
67
|
{"routes":\[
|
68
68
|
{"method":"GET","route":"/foo","statusCode":200,
|
69
69
|
"time":"2018-01-01T00:00:00\+00:00","count":1,"sum":24.0,
|
70
|
-
"sumsq":576.0,"
|
70
|
+
"sumsq":576.0,"tDigest":"AAAAAkBZAAAAAAAAAAAAAUHAAAAB"},
|
71
71
|
{"method":"POST","route":"/foo","statusCode":200,
|
72
72
|
"time":"2018-01-01T00:00:00\+00:00","count":1,"sum":10.0,
|
73
|
-
"sumsq":100.0,"
|
73
|
+
"sumsq":100.0,"tDigest":"AAAAAkBZAAAAAAAAAAAAAUEgAAAB"}\]}
|
74
74
|
\z|x
|
75
75
|
)
|
76
76
|
).to have_been_made
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airbrake-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.rc.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: 2018-10-
|
11
|
+
date: 2018-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tdigest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.1
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rspec
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,12 +118,11 @@ description: |
|
|
104
118
|
Airbrake Ruby is a plain Ruby notifier for Airbrake (https://airbrake.io), the
|
105
119
|
leading exception reporting service. Airbrake Ruby provides minimalist API that
|
106
120
|
enables the ability to send any Ruby exception to the Airbrake dashboard. The
|
107
|
-
library is extremely lightweight
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
Sidekiq, Delayed Job and many more.
|
121
|
+
library is extremely lightweight and it perfectly suits plain Ruby applications.
|
122
|
+
For apps that are built with Rails, Sinatra or any other Rack-compliant web
|
123
|
+
framework we offer the airbrake gem (https://github.com/airbrake/airbrake). It
|
124
|
+
has additional features such as reporting of any unhandled exceptions
|
125
|
+
automatically, integrations with Resque, Sidekiq, Delayed Job and many more.
|
113
126
|
email: support@airbrake.io
|
114
127
|
executables: []
|
115
128
|
extensions: []
|
@@ -194,7 +207,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
207
|
requirements:
|
195
208
|
- - ">="
|
196
209
|
- !ruby/object:Gem::Version
|
197
|
-
version: '2.
|
210
|
+
version: '2.1'
|
198
211
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
199
212
|
requirements:
|
200
213
|
- - ">"
|