airbrake-ruby 1.6.0 → 1.7.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 +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
|