airbrake-ruby 1.6.0 → 1.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 +3 -12
- data/lib/airbrake-ruby/async_sender.rb +10 -7
- data/lib/airbrake-ruby/backtrace.rb +7 -2
- data/lib/airbrake-ruby/config.rb +4 -6
- data/lib/airbrake-ruby/filter_chain.rb +3 -0
- data/lib/airbrake-ruby/nested_exception.rb +3 -0
- data/lib/airbrake-ruby/notice.rb +21 -0
- data/lib/airbrake-ruby/notifier.rb +15 -9
- data/lib/airbrake-ruby/payload_truncator.rb +4 -7
- data/lib/airbrake-ruby/promise.rb +103 -0
- data/lib/airbrake-ruby/response.rb +4 -1
- data/lib/airbrake-ruby/sync_sender.rb +12 -8
- data/lib/airbrake-ruby/version.rb +1 -1
- data/spec/async_sender_spec.rb +2 -2
- data/spec/backtrace_spec.rb +10 -6
- data/spec/config_spec.rb +25 -0
- data/spec/notice_spec.rb +8 -0
- data/spec/notifier_spec.rb +15 -3
- data/spec/notifier_spec/options_spec.rb +3 -2
- data/spec/payload_truncator_spec.rb +2 -12
- data/spec/promise_spec.rb +169 -0
- data/spec/sync_sender_spec.rb +8 -3
- metadata +23 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4447483250d34ac608ceac9356647902e55a8c58
|
4
|
+
data.tar.gz: 550d498d5f8f36b5cff9a4f02a45e813646c2833
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4913a170dcebd29645730f83bba8135a251b07f77f57933eefcaa596b22ad44db84599dbe444ea8bd6fcee57407351f4e1caab8c9d71b292506aa8a89242894e
|
7
|
+
data.tar.gz: d471bba8e00eb16117d6eb8a8842becff961f69d7e3fedfe878fa94939c2aad5919bf9ed5393c91e875995b07de2c4c3c4ae72839b1c600ac4a97f021d651176
|
data/lib/airbrake-ruby.rb
CHANGED
@@ -8,6 +8,7 @@ require 'socket'
|
|
8
8
|
require 'airbrake-ruby/version'
|
9
9
|
require 'airbrake-ruby/config'
|
10
10
|
require 'airbrake-ruby/config/validator'
|
11
|
+
require 'airbrake-ruby/promise'
|
11
12
|
require 'airbrake-ruby/sync_sender'
|
12
13
|
require 'airbrake-ruby/async_sender'
|
13
14
|
require 'airbrake-ruby/response'
|
@@ -55,6 +56,7 @@ require 'airbrake-ruby/notifier'
|
|
55
56
|
# Airbrake.notify('Oops', params, :my_other_project)
|
56
57
|
#
|
57
58
|
# @see Airbrake::Notifier
|
59
|
+
# @since v1.0.0
|
58
60
|
module Airbrake
|
59
61
|
##
|
60
62
|
# The general error that this library uses when it wants to raise.
|
@@ -64,11 +66,6 @@ module Airbrake
|
|
64
66
|
# @return [String] the label to be prepended to the log output
|
65
67
|
LOG_LABEL = '**Airbrake:'.freeze
|
66
68
|
|
67
|
-
##
|
68
|
-
# @return [Boolean] true if current Ruby is Ruby 1.9.*. The result is used
|
69
|
-
# for special cases where we need to work around older implementations
|
70
|
-
RUBY_19 = RUBY_VERSION.start_with?('1.9')
|
71
|
-
|
72
69
|
##
|
73
70
|
# @return [Boolean] true if current Ruby is Ruby 2.0.*. The result is used
|
74
71
|
# for special cases where we need to work around older implementations
|
@@ -140,7 +137,7 @@ module Airbrake
|
|
140
137
|
# @param [Hash] params The additional payload to be sent to Airbrake. Can
|
141
138
|
# contain any values. The provided values will be displayed in the Params
|
142
139
|
# tab in your project's dashboard
|
143
|
-
# @return [
|
140
|
+
# @return [Airbrake::Promise]
|
144
141
|
# @see .notify_sync
|
145
142
|
def notify(exception, params = {}, notifier = :default)
|
146
143
|
call_notifier(notifier, __method__, exception, params)
|
@@ -156,7 +153,6 @@ module Airbrake
|
|
156
153
|
#
|
157
154
|
# @return [Hash{String=>String}] the reponse from the server
|
158
155
|
# @see .notify
|
159
|
-
# @since v5.0.0
|
160
156
|
def notify_sync(exception, params = {}, notifier = :default)
|
161
157
|
call_notifier(notifier, __method__, exception, params)
|
162
158
|
end
|
@@ -187,7 +183,6 @@ module Airbrake
|
|
187
183
|
# @yieldparam [Airbrake::Notice]
|
188
184
|
# @yieldreturn [void]
|
189
185
|
# @return [void]
|
190
|
-
# @since v5.0.0
|
191
186
|
# @note Once a filter was added, there's no way to delete it
|
192
187
|
def add_filter(filter = nil, notifier = :default, &block)
|
193
188
|
call_notifier(notifier, __method__, filter, &block)
|
@@ -209,7 +204,6 @@ module Airbrake
|
|
209
204
|
# @param [Hash] params The additional params attached to the notice
|
210
205
|
# @return [Airbrake::Notice] the notice built with help of the given
|
211
206
|
# arguments
|
212
|
-
# @since v5.0.0
|
213
207
|
def build_notice(exception, params = {}, notifier = :default)
|
214
208
|
call_notifier(notifier, __method__, exception, params)
|
215
209
|
end
|
@@ -225,7 +219,6 @@ module Airbrake
|
|
225
219
|
# Airbrake.notify('App crashed!') #=> raises Airbrake::Error
|
226
220
|
#
|
227
221
|
# @return [void]
|
228
|
-
# @since v5.0.0
|
229
222
|
def close(notifier = :default)
|
230
223
|
call_notifier(notifier, __method__)
|
231
224
|
end
|
@@ -242,8 +235,6 @@ module Airbrake
|
|
242
235
|
# @option deploy_params [Symbol] :revision
|
243
236
|
# @option deploy_params [Symbol] :version
|
244
237
|
# @return [void]
|
245
|
-
# @since v5.0.0
|
246
|
-
# @api private
|
247
238
|
def create_deploy(deploy_params, notifier = :default)
|
248
239
|
call_notifier(notifier, __method__, deploy_params)
|
249
240
|
end
|
@@ -5,6 +5,8 @@ module Airbrake
|
|
5
5
|
# (both values are configurable).
|
6
6
|
#
|
7
7
|
# @see SyncSender
|
8
|
+
# @api private
|
9
|
+
# @since v1.0.0
|
8
10
|
class AsyncSender
|
9
11
|
##
|
10
12
|
# @param [Airbrake::Config] config
|
@@ -23,12 +25,12 @@ module Airbrake
|
|
23
25
|
#
|
24
26
|
# @param [Airbrake::Notice] notice A notice that was generated by the
|
25
27
|
# library
|
26
|
-
# @return [
|
27
|
-
def send(notice)
|
28
|
+
# @return [Airbrake::Promise]
|
29
|
+
def send(notice, promise)
|
28
30
|
return will_not_deliver(notice) if @unsent.size >= @unsent.max
|
29
31
|
|
30
|
-
@unsent << notice
|
31
|
-
|
32
|
+
@unsent << [notice, promise]
|
33
|
+
promise
|
32
34
|
end
|
33
35
|
|
34
36
|
##
|
@@ -48,7 +50,7 @@ module Airbrake
|
|
48
50
|
@config.logger.debug(msg + ' (Ctrl-C to abort)')
|
49
51
|
end
|
50
52
|
|
51
|
-
@config.workers.times { @unsent << :stop }
|
53
|
+
@config.workers.times { @unsent << [:stop, Airbrake::Promise.new] }
|
52
54
|
@closed = true
|
53
55
|
@workers.list.dup
|
54
56
|
end
|
@@ -100,8 +102,9 @@ module Airbrake
|
|
100
102
|
|
101
103
|
def spawn_worker
|
102
104
|
Thread.new do
|
103
|
-
while (
|
104
|
-
|
105
|
+
while (message = @unsent.pop)
|
106
|
+
break if message.first == :stop
|
107
|
+
@sender.send(*message)
|
105
108
|
end
|
106
109
|
end
|
107
110
|
end
|
@@ -10,6 +10,9 @@ module Airbrake
|
|
10
10
|
# rescue
|
11
11
|
# Backtrace.parse($!, Logger.new(STDOUT))
|
12
12
|
# end
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since v1.0.0
|
13
16
|
module Backtrace
|
14
17
|
module Patterns
|
15
18
|
##
|
@@ -32,6 +35,8 @@ module Airbrake
|
|
32
35
|
(?<file>
|
33
36
|
(?:uri:classloader:/.+(?=:)) # Matches '/META-INF/jruby.home/protocol.rb'
|
34
37
|
|
|
38
|
+
(?:uri_3a_classloader_3a_.+(?=:)) # Matches 'uri_3a_classloader_3a_/gems/...'
|
39
|
+
|
|
35
40
|
[^:]+ # Matches 'NewlineNode.java'
|
36
41
|
)
|
37
42
|
:?
|
@@ -151,8 +156,8 @@ module Airbrake
|
|
151
156
|
return false unless defined?(ExecJS::RuntimeError)
|
152
157
|
return true if exception.is_a?(ExecJS::RuntimeError)
|
153
158
|
|
154
|
-
if Airbrake::
|
155
|
-
# Ruby 1
|
159
|
+
if Airbrake::RUBY_20
|
160
|
+
# Ruby <2.1 doesn't support Exception#cause. We work around this by
|
156
161
|
# parsing backtraces. It's slow, so we check only a few first frames.
|
157
162
|
exception.backtrace[0..2].each do |frame|
|
158
163
|
return true if frame =~ Patterns::EXECJS_SIMPLIFIED
|
data/lib/airbrake-ruby/config.rb
CHANGED
@@ -2,6 +2,9 @@ module Airbrake
|
|
2
2
|
##
|
3
3
|
# Represents the Airbrake config. A config contains all the options that you
|
4
4
|
# can use to configure an Airbrake instance.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since v1.0.0
|
5
8
|
class Config
|
6
9
|
##
|
7
10
|
# @return [Integer] the project identificator. This value *must* be set.
|
@@ -103,7 +106,7 @@ module Airbrake
|
|
103
106
|
@endpoint ||=
|
104
107
|
begin
|
105
108
|
self.host = ('https://' << host) if host !~ %r{\Ahttps?://}
|
106
|
-
api = "
|
109
|
+
api = "api/v3/projects/#{project_id}/notices?key=#{project_key}"
|
107
110
|
URI.join(host, api)
|
108
111
|
end
|
109
112
|
end
|
@@ -163,10 +166,5 @@ module Airbrake
|
|
163
166
|
rescue NoMethodError
|
164
167
|
raise Airbrake::Error, "unknown option '#{option}'"
|
165
168
|
end
|
166
|
-
|
167
|
-
def set_endpoint(id, key, host)
|
168
|
-
host = ('https://' << host) if host !~ %r{\Ahttps?://}
|
169
|
-
@endpoint = URI.join(host, "/api/v3/projects/#{id}/notices?key=#{key}")
|
170
|
-
end
|
171
169
|
end
|
172
170
|
end
|
@@ -2,6 +2,9 @@ module Airbrake
|
|
2
2
|
##
|
3
3
|
# A class that is capable of unwinding nested exceptions and representing them
|
4
4
|
# as JSON-like hash.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since v1.0.4
|
5
8
|
class NestedException
|
6
9
|
##
|
7
10
|
# @return [Integer] the maximum number of nested exceptions that a notice
|
data/lib/airbrake-ruby/notice.rb
CHANGED
@@ -2,6 +2,8 @@ module Airbrake
|
|
2
2
|
##
|
3
3
|
# Represents a chunk of information that is meant to be either sent to
|
4
4
|
# Airbrake or ignored completely.
|
5
|
+
#
|
6
|
+
# @since v1.0.0
|
5
7
|
# rubocop:disable Metrics/ClassLength
|
6
8
|
class Notice
|
7
9
|
##
|
@@ -54,6 +56,12 @@ module Airbrake
|
|
54
56
|
# @return [String] the name of the host machine
|
55
57
|
HOSTNAME = Socket.gethostname.freeze
|
56
58
|
|
59
|
+
##
|
60
|
+
# @since v1.7.0
|
61
|
+
# @return [Hash{Symbol=>Object}] the hash with arbitrary objects to be used
|
62
|
+
# in filters
|
63
|
+
attr_reader :stash
|
64
|
+
|
57
65
|
def initialize(config, exception, params = {})
|
58
66
|
@config = config
|
59
67
|
|
@@ -64,6 +72,7 @@ module Airbrake
|
|
64
72
|
session: {},
|
65
73
|
params: params
|
66
74
|
}
|
75
|
+
@stash = {}
|
67
76
|
|
68
77
|
extract_custom_attributes(exception)
|
69
78
|
|
@@ -140,6 +149,17 @@ module Airbrake
|
|
140
149
|
private
|
141
150
|
|
142
151
|
def context(params)
|
152
|
+
# DEPRECATION: remove the following code in the next MINOR release.
|
153
|
+
if params.key?(:component) || params.key?(:action)
|
154
|
+
@config.logger.warn(
|
155
|
+
"#{LOG_LABEL} passing component/action keys in the params hash is " \
|
156
|
+
"deprecated and will be removed soon. Please update your code to use " \
|
157
|
+
"`Airbrake.build_notice` and set these keys like this:\n" \
|
158
|
+
" notice[:context][:component] = 'mycomponent'\n" \
|
159
|
+
" notice[:context][:action] = 'myaction'"
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
143
163
|
ctx = {
|
144
164
|
version: @config.app_version,
|
145
165
|
# We ensure that root_directory is always a String, so it can always be
|
@@ -148,6 +168,7 @@ module Airbrake
|
|
148
168
|
rootDirectory: @config.root_directory.to_s,
|
149
169
|
environment: @config.environment,
|
150
170
|
|
171
|
+
# DEPRECATION: remove the following code in the next MINOR release.
|
151
172
|
# Legacy Airbrake v4 behaviour.
|
152
173
|
component: params.delete(:component),
|
153
174
|
action: params.delete(:action),
|
@@ -5,7 +5,7 @@ module Airbrake
|
|
5
5
|
#
|
6
6
|
# @see Airbrake::Config The list of options
|
7
7
|
# @api private
|
8
|
-
# @since
|
8
|
+
# @since v1.0.0
|
9
9
|
class Notifier
|
10
10
|
##
|
11
11
|
# @return [String] the label to be prepended to the log output
|
@@ -49,14 +49,13 @@ module Airbrake
|
|
49
49
|
##
|
50
50
|
# @macro see_public_api_method
|
51
51
|
def notify(exception, params = {})
|
52
|
-
send_notice(exception, params)
|
53
|
-
nil
|
52
|
+
send_notice(exception, params, default_sender)
|
54
53
|
end
|
55
54
|
|
56
55
|
##
|
57
56
|
# @macro see_public_api_method
|
58
57
|
def notify_sync(exception, params = {})
|
59
|
-
send_notice(exception, params, @sync_sender)
|
58
|
+
send_notice(exception, params, @sync_sender).value
|
60
59
|
end
|
61
60
|
|
62
61
|
##
|
@@ -95,7 +94,9 @@ module Airbrake
|
|
95
94
|
host = @config.endpoint.to_s.split(@config.endpoint.path).first
|
96
95
|
path = "/api/v4/projects/#{@config.project_id}/deploys?key=#{@config.project_key}"
|
97
96
|
|
98
|
-
|
97
|
+
promise = Airbrake::Promise.new
|
98
|
+
@sync_sender.send(deploy_params, promise, URI.join(host, path))
|
99
|
+
promise
|
99
100
|
end
|
100
101
|
|
101
102
|
private
|
@@ -114,14 +115,19 @@ module Airbrake
|
|
114
115
|
e
|
115
116
|
end
|
116
117
|
|
117
|
-
def send_notice(exception, params, sender
|
118
|
-
|
118
|
+
def send_notice(exception, params, sender)
|
119
|
+
promise = Airbrake::Promise.new
|
120
|
+
if @config.ignored_environment?
|
121
|
+
return promise.reject("The '#{@config.environment}' environment is ignored")
|
122
|
+
end
|
119
123
|
|
120
124
|
notice = build_notice(exception, params)
|
121
125
|
@filter_chain.refine(notice)
|
122
|
-
|
126
|
+
if notice.ignored?
|
127
|
+
return promise.reject("#{notice} was marked as ignored")
|
128
|
+
end
|
123
129
|
|
124
|
-
sender.send(notice)
|
130
|
+
sender.send(notice, promise)
|
125
131
|
end
|
126
132
|
|
127
133
|
def default_sender
|
@@ -2,6 +2,9 @@ module Airbrake
|
|
2
2
|
##
|
3
3
|
# This class is responsible for truncation of too big objects. Mainly, you
|
4
4
|
# should use it for simple objects such as strings, hashes, & arrays.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since v1.0.0
|
5
8
|
class PayloadTruncator
|
6
9
|
##
|
7
10
|
# @return [Hash] the options for +String#encode+
|
@@ -10,7 +13,7 @@ module Airbrake
|
|
10
13
|
##
|
11
14
|
# @return [String] the temporary encoding to be used when fixing invalid
|
12
15
|
# strings with +ENCODING_OPTIONS+
|
13
|
-
TEMP_ENCODING =
|
16
|
+
TEMP_ENCODING = 'utf-16'.freeze
|
14
17
|
|
15
18
|
##
|
16
19
|
# @param [Integer] max_size maximum size of hashes, arrays and strings
|
@@ -99,12 +102,6 @@ module Airbrake
|
|
99
102
|
##
|
100
103
|
# Replaces invalid characters in string with arbitrary encoding.
|
101
104
|
#
|
102
|
-
# For Ruby 1.9.2 the method converts encoding of +str+ to +iso-8859-1+ to
|
103
|
-
# avoid a bug when encoding options are no-op, when `#encode` is given the
|
104
|
-
# same encoding as the receiver's encoding.
|
105
|
-
#
|
106
|
-
# For modern Rubies we use UTF-16 as a safe alternative.
|
107
|
-
#
|
108
105
|
# @param [String] str The string to replace characters
|
109
106
|
# @return [String] a UTF-8 encoded string
|
110
107
|
# @note This method mutates +str+ unless it's frozen,
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Airbrake
|
2
|
+
##
|
3
|
+
# Represents a simplified promise object (similar to promises found in
|
4
|
+
# JavaScript), which allows chaining callbacks that are executed when the
|
5
|
+
# promise is either resolved or rejected.
|
6
|
+
#
|
7
|
+
# @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
8
|
+
# @see https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent/promise.rb
|
9
|
+
# @since v1.7.0
|
10
|
+
class Promise
|
11
|
+
##
|
12
|
+
# @return [Hash<String,String>] either successful response containing the
|
13
|
+
# `id` key or unsuccessful response containing the `error` key
|
14
|
+
attr_reader :value
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@on_resolved = []
|
18
|
+
@on_rejected = []
|
19
|
+
@value = {}
|
20
|
+
@mutex = Mutex.new
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Attaches a callback to be executed when the promise is resolved.
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# Airbrake::Promise.new.then { |response| puts response }
|
28
|
+
# #=> {"id"=>"00054415-8201-e9c6-65d6-fc4d231d2871",
|
29
|
+
# # "url"=>"http://localhost/locate/00054415-8201-e9c6-65d6-fc4d231d2871"}
|
30
|
+
#
|
31
|
+
# @yield [response]
|
32
|
+
# @yieldparam response [Hash<String,String>] Contains the `id` & `url` keys
|
33
|
+
# @return [self]
|
34
|
+
def then(&block)
|
35
|
+
@mutex.synchronize do
|
36
|
+
if @value.key?('id')
|
37
|
+
yield(@value)
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
@on_resolved << block
|
42
|
+
end
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Attaches a callback to be executed when the promise is rejected.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Airbrake::Promise.new.rescue { |error| raise error }
|
52
|
+
#
|
53
|
+
# @yield [error] The error message from the API
|
54
|
+
# @yieldparam error [String]
|
55
|
+
# @return [self]
|
56
|
+
def rescue(&block)
|
57
|
+
@mutex.synchronize do
|
58
|
+
if @value.key?('error')
|
59
|
+
yield(@value['error'])
|
60
|
+
return self
|
61
|
+
end
|
62
|
+
|
63
|
+
@on_rejected << block
|
64
|
+
end
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Resolves the promise.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# Airbrake::Promise.new.resolve('id' => '123')
|
74
|
+
#
|
75
|
+
# @param response [Hash<String,String>]
|
76
|
+
# @return [self]
|
77
|
+
def resolve(response)
|
78
|
+
@mutex.synchronize do
|
79
|
+
@value = response
|
80
|
+
@on_resolved.each { |callback| callback.call(response) }
|
81
|
+
end
|
82
|
+
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Rejects the promise.
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# Airbrake::Promise.new.reject('Something went wrong')
|
91
|
+
#
|
92
|
+
# @param error [String]
|
93
|
+
# @return [self]
|
94
|
+
def reject(error)
|
95
|
+
@mutex.synchronize do
|
96
|
+
@value['error'] = error
|
97
|
+
@on_rejected.each { |callback| callback.call(error) }
|
98
|
+
end
|
99
|
+
|
100
|
+
self
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -2,6 +2,9 @@ module Airbrake
|
|
2
2
|
##
|
3
3
|
# Parses responses coming from the Airbrake API. Handles HTTP errors by
|
4
4
|
# logging them.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @since v1.0.0
|
5
8
|
module Response
|
6
9
|
##
|
7
10
|
# @return [Integer] the limit of the response body
|
@@ -35,7 +38,7 @@ module Airbrake
|
|
35
38
|
rescue => ex
|
36
39
|
body_msg = truncated_body(body)
|
37
40
|
logger.error("#{LOG_LABEL} error while parsing body (#{ex}). Body: #{body_msg}")
|
38
|
-
{ 'error' => ex }
|
41
|
+
{ 'error' => ex.inspect }
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
@@ -3,6 +3,8 @@ module Airbrake
|
|
3
3
|
# Responsible for sending notices to Airbrake synchronously. Supports proxies.
|
4
4
|
#
|
5
5
|
# @see AsyncSender
|
6
|
+
# @api private
|
7
|
+
# @since v1.0.0
|
6
8
|
class SyncSender
|
7
9
|
##
|
8
10
|
# @return [String] body for HTTP requests
|
@@ -20,15 +22,14 @@ module Airbrake
|
|
20
22
|
# @param [Airbrake::Notice] notice
|
21
23
|
# @param [Airbrake::Notice] endpoint
|
22
24
|
# @return [Hash{String=>String}] the parsed HTTP response
|
23
|
-
def send(notice, endpoint = @config.endpoint)
|
25
|
+
def send(notice, promise, endpoint = @config.endpoint)
|
24
26
|
response = nil
|
25
27
|
req = build_post_request(endpoint, notice)
|
26
28
|
|
27
29
|
if req.body.nil?
|
28
|
-
|
29
|
-
|
30
|
-
)
|
31
|
-
return
|
30
|
+
reason = "#{LOG_LABEL} notice was not sent because of missing body"
|
31
|
+
@config.logger.error(reason)
|
32
|
+
return promise.reject(reason)
|
32
33
|
end
|
33
34
|
|
34
35
|
https = build_https(endpoint)
|
@@ -36,11 +37,14 @@ module Airbrake
|
|
36
37
|
begin
|
37
38
|
response = https.request(req)
|
38
39
|
rescue => ex
|
39
|
-
|
40
|
-
|
40
|
+
reason = "#{LOG_LABEL} HTTP error: #{ex}"
|
41
|
+
@config.logger.error(reason)
|
42
|
+
return promise.reject(reason)
|
41
43
|
end
|
42
44
|
|
43
|
-
Response.parse(response, @config.logger)
|
45
|
+
parsed_resp = Response.parse(response, @config.logger)
|
46
|
+
return promise.reject(parsed_resp['error']) if parsed_resp.key?('error')
|
47
|
+
promise.resolve(parsed_resp)
|
44
48
|
end
|
45
49
|
|
46
50
|
private
|
data/spec/async_sender_spec.rb
CHANGED
@@ -17,7 +17,7 @@ RSpec.describe Airbrake::AsyncSender do
|
|
17
17
|
expect(sender).to have_workers
|
18
18
|
|
19
19
|
notice = Airbrake::Notice.new(config, AirbrakeTestError.new)
|
20
|
-
notices_count.times { sender.send(notice) }
|
20
|
+
notices_count.times { sender.send(notice, Airbrake::Promise.new) }
|
21
21
|
sender.close
|
22
22
|
|
23
23
|
log = stdout.string.split("\n")
|
@@ -49,7 +49,7 @@ RSpec.describe Airbrake::AsyncSender do
|
|
49
49
|
context "when there are some unsent notices" do
|
50
50
|
before do
|
51
51
|
notice = Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
52
|
-
300.times { @sender.send(notice) }
|
52
|
+
300.times { @sender.send(notice, Airbrake::Promise.new) }
|
53
53
|
expect(@sender.instance_variable_get(:@unsent).size).not_to be_zero
|
54
54
|
@sender.close
|
55
55
|
end
|
data/spec/backtrace_spec.rb
CHANGED
@@ -80,14 +80,18 @@ RSpec.describe Airbrake::Backtrace do
|
|
80
80
|
let(:backtrace) do
|
81
81
|
# rubocop:disable Metrics/LineLength
|
82
82
|
['uri_3a_classloader_3a_.META_minus_INF.jruby_dot_home.lib.ruby.stdlib.net.protocol.rbuf_fill(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/net/protocol.rb:158)',
|
83
|
-
'bin.processors.image_uploader.block in make_streams(bin/processors/image_uploader.rb:21)'
|
83
|
+
'bin.processors.image_uploader.block in make_streams(bin/processors/image_uploader.rb:21)',
|
84
|
+
'uri_3a_classloader_3a_.gems.faye_minus_websocket_minus_0_dot_10_dot_5.lib.faye.websocket.api.invokeOther13:dispatch_event(uri_3a_classloader_3a_/gems/faye_minus_websocket_minus_0_dot_10_dot_5/lib/faye/websocket/uri:classloader:/gems/faye-websocket-0.10.5/lib/faye/websocket/api.rb:109)',
|
85
|
+
'tmp.jruby9022301782566983632extract.$dot.META_minus_INF.rails.file(/tmp/jruby9022301782566983632extract/./META-INF/rails.rb:13)']
|
84
86
|
# rubocop:enable Metrics/LineLength
|
85
87
|
end
|
86
88
|
|
87
89
|
let(:parsed_backtrace) do
|
88
90
|
# rubocop:disable Metrics/LineLength
|
89
91
|
[{ file: 'uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/net/protocol.rb', line: 158, function: 'uri_3a_classloader_3a_.META_minus_INF.jruby_dot_home.lib.ruby.stdlib.net.protocol.rbuf_fill' },
|
90
|
-
{ file: 'bin/processors/image_uploader.rb', line: 21, function: 'bin.processors.image_uploader.block in make_streams' }
|
92
|
+
{ file: 'bin/processors/image_uploader.rb', line: 21, function: 'bin.processors.image_uploader.block in make_streams' },
|
93
|
+
{ file: 'uri_3a_classloader_3a_/gems/faye_minus_websocket_minus_0_dot_10_dot_5/lib/faye/websocket/uri:classloader:/gems/faye-websocket-0.10.5/lib/faye/websocket/api.rb', line: 109, function: 'uri_3a_classloader_3a_.gems.faye_minus_websocket_minus_0_dot_10_dot_5.lib.faye.websocket.api.invokeOther13:dispatch_event' },
|
94
|
+
{ file: '/tmp/jruby9022301782566983632extract/./META-INF/rails.rb', line: 13, function: 'tmp.jruby9022301782566983632extract.$dot.META_minus_INF.rails.file' }]
|
91
95
|
# rubocop:enable Metrics/LineLength
|
92
96
|
end
|
93
97
|
|
@@ -242,12 +246,12 @@ RSpec.describe Airbrake::Backtrace do
|
|
242
246
|
function: 'realtime' }]
|
243
247
|
end
|
244
248
|
|
245
|
-
context "when not on Ruby
|
249
|
+
context "when not on Ruby 2.0" do
|
246
250
|
let(:ex) { ExecJS::RuntimeError.new.tap { |e| e.set_backtrace(bt) } }
|
247
251
|
|
248
252
|
it "returns a properly formatted array of hashes" do
|
249
253
|
stub_const('ExecJS::RuntimeError', AirbrakeTestError)
|
250
|
-
stub_const('Airbrake::
|
254
|
+
stub_const('Airbrake::RUBY_20', false)
|
251
255
|
|
252
256
|
expect(
|
253
257
|
described_class.parse(ex, Logger.new('/dev/null'))
|
@@ -255,7 +259,7 @@ RSpec.describe Airbrake::Backtrace do
|
|
255
259
|
end
|
256
260
|
end
|
257
261
|
|
258
|
-
context "when on Ruby
|
262
|
+
context "when on Ruby 2.0" do
|
259
263
|
context "and when exception's class isn't ExecJS" do
|
260
264
|
let(:ex) do
|
261
265
|
ActionView::Template::Error.new.tap { |e| e.set_backtrace(bt) }
|
@@ -264,7 +268,7 @@ RSpec.describe Airbrake::Backtrace do
|
|
264
268
|
it "returns a properly formatted array of hashes" do
|
265
269
|
stub_const('ActionView::Template::Error', AirbrakeTestError)
|
266
270
|
stub_const('ExecJS::RuntimeError', NameError)
|
267
|
-
stub_const('Airbrake::
|
271
|
+
stub_const('Airbrake::RUBY_20', true)
|
268
272
|
|
269
273
|
expect(
|
270
274
|
described_class.parse(ex, Logger.new('/dev/null'))
|
data/spec/config_spec.rb
CHANGED
@@ -229,4 +229,29 @@ RSpec.describe Airbrake::Config do
|
|
229
229
|
end
|
230
230
|
end
|
231
231
|
end
|
232
|
+
|
233
|
+
describe "#endpoint" do
|
234
|
+
context "when host is configured with a URL with a slug" do
|
235
|
+
before do
|
236
|
+
config.project_id = 1
|
237
|
+
config.project_key = '2'
|
238
|
+
end
|
239
|
+
|
240
|
+
context "and with a trailing slash" do
|
241
|
+
it "sets the endpoint with the slug" do
|
242
|
+
config.host = 'https://localhost/bingo/'
|
243
|
+
expect(config.endpoint.to_s).
|
244
|
+
to eq('https://localhost/bingo/api/v3/projects/1/notices?key=2')
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context "and without a trailing slash" do
|
249
|
+
it "sets the endpoint without the slug" do
|
250
|
+
config.host = 'https://localhost/bingo'
|
251
|
+
expect(config.endpoint.to_s).
|
252
|
+
to eq('https://localhost/api/v3/projects/1/notices?key=2')
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
232
257
|
end
|
data/spec/notice_spec.rb
CHANGED
@@ -237,4 +237,12 @@ RSpec.describe Airbrake::Notice do
|
|
237
237
|
to raise_error(Airbrake::Error, 'Got Object value, wanted a Hash')
|
238
238
|
end
|
239
239
|
end
|
240
|
+
|
241
|
+
describe "#stash" do
|
242
|
+
it "returns a hash" do
|
243
|
+
obj = Object.new
|
244
|
+
notice.stash[:bingo_object] = obj
|
245
|
+
expect(notice.stash[:bingo_object]).to eql(obj)
|
246
|
+
end
|
247
|
+
end
|
240
248
|
end
|
data/spec/notifier_spec.rb
CHANGED
@@ -23,7 +23,10 @@ RSpec.describe Airbrake::Notifier do
|
|
23
23
|
let(:ex) { AirbrakeTestError.new }
|
24
24
|
|
25
25
|
before do
|
26
|
-
|
26
|
+
# rubocop:disable Metrics/LineLength
|
27
|
+
body = '{"id":"00054414-b147-6ffa-85d6-1524d83362a6","url":"http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6"}'
|
28
|
+
# rubocop:enable Metrics/LineLength
|
29
|
+
stub_request(:post, endpoint).to_return(status: 201, body: body)
|
27
30
|
@airbrake = described_class.new(airbrake_params)
|
28
31
|
end
|
29
32
|
|
@@ -58,6 +61,15 @@ RSpec.describe Airbrake::Notifier do
|
|
58
61
|
end
|
59
62
|
|
60
63
|
describe "#notify_sync" do
|
64
|
+
it "returns a hash with error id & url" do
|
65
|
+
expect(@airbrake.notify_sync(ex)).to(
|
66
|
+
eq(
|
67
|
+
'id' => '00054414-b147-6ffa-85d6-1524d83362a6',
|
68
|
+
'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6'
|
69
|
+
)
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
61
73
|
describe "first argument" do
|
62
74
|
context "when it is a Notice" do
|
63
75
|
it "sends the argument" do
|
@@ -372,8 +384,8 @@ RSpec.describe Airbrake::Notifier do
|
|
372
384
|
expect_a_request_with_body(/params":{"bingo":"bango"}/)
|
373
385
|
end
|
374
386
|
|
375
|
-
it "returns
|
376
|
-
expect(@airbrake.notify(ex)).to
|
387
|
+
it "returns a promise" do
|
388
|
+
expect(@airbrake.notify(ex)).to be_an(Airbrake::Promise)
|
377
389
|
sleep 1
|
378
390
|
end
|
379
391
|
|
@@ -143,7 +143,7 @@ RSpec.describe Airbrake::Notifier do
|
|
143
143
|
it "is being used if configured" do
|
144
144
|
@airbrake.notify_sync(ex)
|
145
145
|
|
146
|
-
proxied_request = requests.pop
|
146
|
+
proxied_request = requests.pop(true)
|
147
147
|
|
148
148
|
expect(proxied_request.header['proxy-authorization'].first).
|
149
149
|
to eq('Basic dXNlcjpwYXNzd29yZA==')
|
@@ -210,7 +210,8 @@ RSpec.describe Airbrake::Notifier do
|
|
210
210
|
airbrake = described_class.new(airbrake_params.merge(params))
|
211
211
|
|
212
212
|
expect(Airbrake::Notice).not_to receive(:new)
|
213
|
-
expect(airbrake.notify_sync(ex)).
|
213
|
+
expect(airbrake.notify_sync(ex)).
|
214
|
+
to eq('error' => "The 'development' environment is ignored")
|
214
215
|
expect(a_request(:post, endpoint)).not_to have_been_made
|
215
216
|
end
|
216
217
|
end
|
@@ -409,12 +409,7 @@ RSpec.describe Airbrake::PayloadTruncator do
|
|
409
409
|
@truncator.truncate_object(params)
|
410
410
|
|
411
411
|
expect(params[:unicode].length).to eq(max_len - 1)
|
412
|
-
|
413
|
-
if RUBY_VERSION == '1.9.2'
|
414
|
-
expect(params[:unicode]).to match(/\A?{#{max_size - 1}}\[Truncated\]\z/)
|
415
|
-
else
|
416
|
-
expect(params[:unicode]).to match(/\A€{#{max_size - 1}}\[Truncated\]\z/)
|
417
|
-
end
|
412
|
+
expect(params[:unicode]).to match(/\A€{#{max_size - 1}}\[Truncated\]\z/)
|
418
413
|
end
|
419
414
|
end
|
420
415
|
|
@@ -425,12 +420,7 @@ RSpec.describe Airbrake::PayloadTruncator do
|
|
425
420
|
it "converts strings to valid UTF-8" do
|
426
421
|
@truncator.truncate_object(params)
|
427
422
|
|
428
|
-
|
429
|
-
expect(params[:unicode]).to eq('bad string??')
|
430
|
-
else
|
431
|
-
expect(params[:unicode]).to match(/\Abad string€[�\?]\z/)
|
432
|
-
end
|
433
|
-
|
423
|
+
expect(params[:unicode]).to match(/\Abad string€[�\?]\z/)
|
434
424
|
expect { params.to_json }.not_to raise_error
|
435
425
|
end
|
436
426
|
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Airbrake::Promise do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe ".then" do
|
7
|
+
let(:resolved_with) { [] }
|
8
|
+
let(:rejected_with) { [] }
|
9
|
+
|
10
|
+
context "when it is not resolved" do
|
11
|
+
it "returns self" do
|
12
|
+
expect(subject.then {}).to eq(subject)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "doesn't call the resolve callbacks yet" do
|
16
|
+
subject.then { resolved_with << 1 }.then { resolved_with << 2 }
|
17
|
+
expect(resolved_with).to be_empty
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when it is resolved" do
|
22
|
+
shared_examples "then specs" do
|
23
|
+
it "returns self" do
|
24
|
+
expect(subject.then {}).to eq(subject)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "yields the resolved value" do
|
28
|
+
yielded = nil
|
29
|
+
subject.then { |value| yielded = value }
|
30
|
+
expect(yielded).to eq('id' => '123')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "calls the resolve callbacks" do
|
34
|
+
expect(resolved_with).to match_array([1, 2])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "doesn't call the reject callbacks" do
|
38
|
+
expect(rejected_with).to be_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "and there are some resolve and reject callbacks in place" do
|
43
|
+
before do
|
44
|
+
subject.then { resolved_with << 1 }.then { resolved_with << 2 }
|
45
|
+
subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
|
46
|
+
subject.resolve('id' => '123')
|
47
|
+
end
|
48
|
+
|
49
|
+
include_examples "then specs"
|
50
|
+
|
51
|
+
it "registers the resolve callbacks" do
|
52
|
+
subject.resolve('id' => '456')
|
53
|
+
expect(resolved_with).to match_array([1, 2, 1, 2])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "and additional then callbacks are added" do
|
58
|
+
before do
|
59
|
+
subject.resolve('id' => '123')
|
60
|
+
subject.then { resolved_with << 1 }.then { resolved_with << 2 }
|
61
|
+
end
|
62
|
+
|
63
|
+
include_examples "then specs"
|
64
|
+
|
65
|
+
it "doesn't register new resolve callbacks" do
|
66
|
+
subject.resolve('id' => '456')
|
67
|
+
expect(resolved_with).to match_array([1, 2])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe ".rescue" do
|
74
|
+
let(:resolved_with) { [] }
|
75
|
+
let(:rejected_with) { [] }
|
76
|
+
|
77
|
+
context "when it is not rejected" do
|
78
|
+
it "returns self" do
|
79
|
+
expect(subject.then {}).to eq(subject)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "doesn't call the reject callbacks yet" do
|
83
|
+
subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
|
84
|
+
expect(rejected_with).to be_empty
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when it is rejected" do
|
89
|
+
shared_examples "rescue specs" do
|
90
|
+
it "returns self" do
|
91
|
+
expect(subject.rescue {}).to eq(subject)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "yields the rejected value" do
|
95
|
+
yielded = nil
|
96
|
+
subject.rescue { |value| yielded = value }
|
97
|
+
expect(yielded).to eq('bingo')
|
98
|
+
end
|
99
|
+
|
100
|
+
it "doesn't call the resolve callbacks" do
|
101
|
+
expect(resolved_with).to be_empty
|
102
|
+
end
|
103
|
+
|
104
|
+
it "calls the reject callbacks" do
|
105
|
+
expect(rejected_with).to match_array([1, 2])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "and there are some resolve and reject callbacks in place" do
|
110
|
+
before do
|
111
|
+
subject.then { resolved_with << 1 }.then { resolved_with << 2 }
|
112
|
+
subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
|
113
|
+
subject.reject('bingo')
|
114
|
+
end
|
115
|
+
|
116
|
+
include_examples "rescue specs"
|
117
|
+
|
118
|
+
it "registers the reject callbacks" do
|
119
|
+
subject.reject('bingo again')
|
120
|
+
expect(rejected_with).to match_array([1, 2, 1, 2])
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "and additional reject callbacks are added" do
|
125
|
+
before do
|
126
|
+
subject.reject('bingo')
|
127
|
+
subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
|
128
|
+
end
|
129
|
+
|
130
|
+
include_examples "rescue specs"
|
131
|
+
|
132
|
+
it "doesn't register new reject callbacks" do
|
133
|
+
subject.reject('bingo again')
|
134
|
+
expect(rejected_with).to match_array([1, 2])
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe ".resolve" do
|
141
|
+
it "returns self" do
|
142
|
+
expect(subject.resolve(1)).to eq(subject)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "executes callbacks attached with .then" do
|
146
|
+
array = []
|
147
|
+
subject.then { |notice_id| array << notice_id }.rescue { array << 999 }
|
148
|
+
|
149
|
+
expect(array.size).to be_zero
|
150
|
+
subject.resolve(1)
|
151
|
+
expect(array).to match_array([1])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe ".reject" do
|
156
|
+
it "returns self" do
|
157
|
+
expect(subject.reject(1)).to eq(subject)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "executes callbacks attached with .rescue" do
|
161
|
+
array = []
|
162
|
+
subject.then { array << 1 }.rescue { |error| array << error }
|
163
|
+
|
164
|
+
expect(array.size).to be_zero
|
165
|
+
subject.reject(999)
|
166
|
+
expect(array).to match_array([999])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/spec/sync_sender_spec.rb
CHANGED
@@ -12,7 +12,9 @@ RSpec.describe Airbrake::SyncSender do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "#send" do
|
15
|
-
|
15
|
+
let(:promise) { Airbrake::Promise.new }
|
16
|
+
|
17
|
+
it "catches exceptions raised while sending" do
|
16
18
|
stdout = StringIO.new
|
17
19
|
config = Airbrake::Config.new(logger: Logger.new(stdout))
|
18
20
|
sender = described_class.new(config)
|
@@ -20,7 +22,8 @@ RSpec.describe Airbrake::SyncSender do
|
|
20
22
|
https = double("foo")
|
21
23
|
allow(sender).to receive(:build_https).and_return(https)
|
22
24
|
allow(https).to receive(:request).and_raise(StandardError.new('foo'))
|
23
|
-
expect(sender.send(notice)).to
|
25
|
+
expect(sender.send(notice, promise)).to be_an(Airbrake::Promise)
|
26
|
+
expect(promise.value).to eq('error' => '**Airbrake: HTTP error: foo')
|
24
27
|
expect(stdout.string).to match(/ERROR -- : .+ HTTP error: foo/)
|
25
28
|
end
|
26
29
|
|
@@ -43,7 +46,9 @@ RSpec.describe Airbrake::SyncSender do
|
|
43
46
|
sender = described_class.new(config)
|
44
47
|
notice = Airbrake::Notice.new(config, ex)
|
45
48
|
|
46
|
-
expect(sender.send(notice)).to
|
49
|
+
expect(sender.send(notice, promise)).to be_an(Airbrake::Promise)
|
50
|
+
expect(promise.value).
|
51
|
+
to match('error' => '**Airbrake: notice was not sent because of missing body')
|
47
52
|
expect(stdout.string).to match(/ERROR -- : .+ notice was not sent/)
|
48
53
|
end
|
49
54
|
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: 1.
|
4
|
+
version: 1.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:
|
11
|
+
date: 2017-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '2'
|
61
|
+
version: '2.3'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '2'
|
68
|
+
version: '2.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: benchmark-ips
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.47'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.47'
|
83
97
|
description: |
|
84
98
|
Airbrake Ruby is a plain Ruby notifier for Airbrake (https://airbrake.io), the
|
85
99
|
leading exception reporting service. Airbrake Ruby provides minimalist API that
|
@@ -109,6 +123,7 @@ files:
|
|
109
123
|
- lib/airbrake-ruby/notice.rb
|
110
124
|
- lib/airbrake-ruby/notifier.rb
|
111
125
|
- lib/airbrake-ruby/payload_truncator.rb
|
126
|
+
- lib/airbrake-ruby/promise.rb
|
112
127
|
- lib/airbrake-ruby/response.rb
|
113
128
|
- lib/airbrake-ruby/sync_sender.rb
|
114
129
|
- lib/airbrake-ruby/version.rb
|
@@ -125,6 +140,7 @@ files:
|
|
125
140
|
- spec/notifier_spec/options_spec.rb
|
126
141
|
- spec/notifier_spec/whitelist_keys_spec.rb
|
127
142
|
- spec/payload_truncator_spec.rb
|
143
|
+
- spec/promise_spec.rb
|
128
144
|
- spec/spec_helper.rb
|
129
145
|
- spec/sync_sender_spec.rb
|
130
146
|
homepage: https://airbrake.io
|
@@ -139,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
155
|
requirements:
|
140
156
|
- - ">="
|
141
157
|
- !ruby/object:Gem::Version
|
142
|
-
version: '0'
|
158
|
+
version: '2.0'
|
143
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
160
|
requirements:
|
145
161
|
- - ">="
|
@@ -147,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
163
|
version: '0'
|
148
164
|
requirements: []
|
149
165
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.
|
166
|
+
rubygems_version: 2.6.8
|
151
167
|
signing_key:
|
152
168
|
specification_version: 4
|
153
169
|
summary: Ruby notifier for https://airbrake.io
|
@@ -165,5 +181,6 @@ test_files:
|
|
165
181
|
- spec/notifier_spec/whitelist_keys_spec.rb
|
166
182
|
- spec/notifier_spec.rb
|
167
183
|
- spec/payload_truncator_spec.rb
|
184
|
+
- spec/promise_spec.rb
|
168
185
|
- spec/spec_helper.rb
|
169
186
|
- spec/sync_sender_spec.rb
|