ratchetio 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +3 -0
- data/README.md +10 -0
- data/THANKS +1 -0
- data/lib/ratchetio/version.rb +1 -1
- data/lib/ratchetio.rb +63 -34
- data/spec/dummyapp/app/controllers/home_controller.rb +1 -1
- data/spec/ratchetio_spec.rb +59 -42
- metadata +1 -1
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
**0.5.3**
|
4
|
+
- Add `Ratchetio.silenced`; which allows disabling reporting for a given block. See README for usage.
|
5
|
+
|
3
6
|
**0.5.2**
|
4
7
|
- Fix compat issue with delayed_job below version 3. Exceptions raised by delayed_job below version 3 will not be automatically caught; upgrade to v3 or catch and report by hand.
|
5
8
|
|
data/README.md
CHANGED
@@ -94,6 +94,16 @@ By default, all exceptions reported through `Ratchetio.report_exception()` are r
|
|
94
94
|
If you'd like to customize this list, see the example code in `config/initializers/ratchetio.rb`. Supported levels: "critical", "error", "warning", "info", "debug", "ignore". Set to "ignore" to cause the exception not to be reported at all.
|
95
95
|
|
96
96
|
|
97
|
+
## Silencing exceptions at runtime
|
98
|
+
|
99
|
+
If you just want to disable exception reporting for a single block, use `Ratchetio.silenced`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Ratchetio.silenced {
|
103
|
+
foo = bar # will not be reported
|
104
|
+
}
|
105
|
+
```
|
106
|
+
|
97
107
|
|
98
108
|
## Asynchronous reporting
|
99
109
|
|
data/THANKS
CHANGED
data/lib/ratchetio/version.rb
CHANGED
data/lib/ratchetio.rb
CHANGED
@@ -15,9 +15,9 @@ require 'ratchetio/version'
|
|
15
15
|
module Ratchetio
|
16
16
|
class << self
|
17
17
|
attr_writer :configuration
|
18
|
-
|
18
|
+
|
19
19
|
# Configures the gem.
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# Call on app startup to set the `access_token` (required) and other config params.
|
22
22
|
# In a Rails app, this is called by `config/initializers/ratchetio.rb` which is generated
|
23
23
|
# with `rails generate ratchetio access-token-here`
|
@@ -29,7 +29,7 @@ module Ratchetio
|
|
29
29
|
def configure
|
30
30
|
yield(configuration)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def reconfigure
|
34
34
|
@configuration = Configuration.new
|
35
35
|
yield(configuration)
|
@@ -52,7 +52,7 @@ module Ratchetio
|
|
52
52
|
# end
|
53
53
|
#
|
54
54
|
# @param exception [Exception] The exception object to report
|
55
|
-
# @param request_data [Hash] Data describing the request. Should be the result of calling
|
55
|
+
# @param request_data [Hash] Data describing the request. Should be the result of calling
|
56
56
|
# `ratchetio_request_data`.
|
57
57
|
# @param person_data [Hash] Data describing the affected person. Should be the result of calling
|
58
58
|
# `ratchetio_person_data`
|
@@ -61,13 +61,11 @@ module Ratchetio
|
|
61
61
|
return
|
62
62
|
end
|
63
63
|
|
64
|
-
|
65
|
-
if filtered_level == 'ignore'
|
66
|
-
# ignored - do nothing
|
64
|
+
if ignored?(exception)
|
67
65
|
return
|
68
66
|
end
|
69
67
|
|
70
|
-
data = exception_data(exception, filtered_level)
|
68
|
+
data = exception_data(exception, filtered_level(exception))
|
71
69
|
data[:request] = request_data if request_data
|
72
70
|
data[:person] = person_data if person_data
|
73
71
|
|
@@ -84,17 +82,17 @@ module Ratchetio
|
|
84
82
|
# @example
|
85
83
|
# Ratchetio.report_message("User login failed", 'info', :user_id => 123)
|
86
84
|
#
|
87
|
-
# @param message [String] The message body. This will be used to identify the message within
|
88
|
-
# Ratchet. For best results, avoid putting variables in the message body; pass them as
|
89
|
-
# `extra_data` instead.
|
85
|
+
# @param message [String] The message body. This will be used to identify the message within
|
86
|
+
# Ratchet. For best results, avoid putting variables in the message body; pass them as
|
87
|
+
# `extra_data` instead.
|
90
88
|
# @param level [String] The level. One of: 'critical', 'error', 'warning', 'info', 'debug'
|
91
|
-
# @param extra_data [Hash] Additional data to include alongside the body. Don't use 'body' as
|
89
|
+
# @param extra_data [Hash] Additional data to include alongside the body. Don't use 'body' as
|
92
90
|
# it is reserved.
|
93
91
|
def report_message(message, level = 'info', extra_data = {})
|
94
92
|
unless configuration.enabled
|
95
93
|
return
|
96
94
|
end
|
97
|
-
|
95
|
+
|
98
96
|
data = message_data(message, level, extra_data)
|
99
97
|
payload = build_payload(data)
|
100
98
|
schedule_payload(payload)
|
@@ -102,6 +100,21 @@ module Ratchetio
|
|
102
100
|
logger.error "[Ratchet.io] Error reporting message to Ratchet.io: #{e}"
|
103
101
|
end
|
104
102
|
|
103
|
+
# Turns off reporting for the given block.
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# Ratchetio.silenced { raise }
|
107
|
+
#
|
108
|
+
# @yield Block which exceptions won't be reported.
|
109
|
+
def silenced
|
110
|
+
begin
|
111
|
+
yield
|
112
|
+
rescue => e
|
113
|
+
e.instance_variable_set(:@_ratchet_do_not_report, true)
|
114
|
+
raise
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
105
118
|
def process_payload(payload)
|
106
119
|
begin
|
107
120
|
if configuration.write_to_file
|
@@ -116,9 +129,25 @@ module Ratchetio
|
|
116
129
|
|
117
130
|
private
|
118
131
|
|
132
|
+
def ignored?(exception)
|
133
|
+
if filtered_level(exception) == 'ignore'
|
134
|
+
return true
|
135
|
+
end
|
136
|
+
|
137
|
+
if exception.instance_variable_get(:@_ratchet_do_not_report)
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
def filtered_level(exception)
|
145
|
+
configuration.exception_level_filters[exception.class.name]
|
146
|
+
end
|
147
|
+
|
119
148
|
def message_data(message, level, extra_data)
|
120
149
|
data = base_data(level)
|
121
|
-
|
150
|
+
|
122
151
|
data[:body] = {
|
123
152
|
:message => {
|
124
153
|
:body => message.to_s
|
@@ -126,13 +155,13 @@ module Ratchetio
|
|
126
155
|
}
|
127
156
|
data[:body][:message].merge!(extra_data)
|
128
157
|
data[:server] = server_data
|
129
|
-
|
158
|
+
|
130
159
|
data
|
131
160
|
end
|
132
161
|
|
133
162
|
def exception_data(exception, force_level = nil)
|
134
163
|
data = base_data
|
135
|
-
|
164
|
+
|
136
165
|
data[:level] = force_level if force_level
|
137
166
|
|
138
167
|
# parse backtrace
|
@@ -159,7 +188,7 @@ module Ratchetio
|
|
159
188
|
}
|
160
189
|
|
161
190
|
data[:server] = server_data
|
162
|
-
|
191
|
+
|
163
192
|
data
|
164
193
|
end
|
165
194
|
|
@@ -170,7 +199,7 @@ module Ratchetio
|
|
170
199
|
end
|
171
200
|
configuration.logger
|
172
201
|
end
|
173
|
-
|
202
|
+
|
174
203
|
def write_payload(payload)
|
175
204
|
if configuration.use_async
|
176
205
|
@file_semaphore.synchronize {
|
@@ -180,15 +209,15 @@ module Ratchetio
|
|
180
209
|
do_write_payload(payload)
|
181
210
|
end
|
182
211
|
end
|
183
|
-
|
212
|
+
|
184
213
|
def do_write_payload(payload)
|
185
214
|
logger.info '[Ratchet.io] Writing payload to file'
|
186
|
-
|
215
|
+
|
187
216
|
begin
|
188
217
|
unless @file
|
189
218
|
@file = File.open(configuration.filepath, "a")
|
190
219
|
end
|
191
|
-
|
220
|
+
|
192
221
|
@file.puts payload
|
193
222
|
@file.flush
|
194
223
|
logger.info "[Ratchet.io] Success"
|
@@ -196,13 +225,13 @@ module Ratchetio
|
|
196
225
|
logger.error "[Ratchet.io] Error opening/writing to file: #{e}"
|
197
226
|
end
|
198
227
|
end
|
199
|
-
|
228
|
+
|
200
229
|
def send_payload(payload)
|
201
230
|
logger.info '[Ratchet.io] Sending payload'
|
202
|
-
|
231
|
+
|
203
232
|
uri = URI.parse(configuration.endpoint)
|
204
233
|
http = Net::HTTP.new(uri.host, uri.port)
|
205
|
-
|
234
|
+
|
206
235
|
if uri.scheme == 'https'
|
207
236
|
http.use_ssl = true
|
208
237
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
@@ -219,21 +248,21 @@ module Ratchetio
|
|
219
248
|
logger.info "[Ratchet.io] Response: #{response.body}"
|
220
249
|
end
|
221
250
|
end
|
222
|
-
|
251
|
+
|
223
252
|
def schedule_payload(payload)
|
224
253
|
logger.info '[Ratchet.io] Scheduling payload'
|
225
|
-
|
254
|
+
|
226
255
|
if configuration.use_async
|
227
256
|
unless configuration.async_handler
|
228
257
|
configuration.async_handler = method(:default_async_handler)
|
229
258
|
end
|
230
|
-
|
259
|
+
|
231
260
|
if configuration.write_to_file
|
232
261
|
unless @file_semaphore
|
233
262
|
@file_semaphore = Mutex.new
|
234
263
|
end
|
235
264
|
end
|
236
|
-
|
265
|
+
|
237
266
|
configuration.async_handler.call(payload)
|
238
267
|
else
|
239
268
|
process_payload(payload)
|
@@ -261,26 +290,26 @@ module Ratchetio
|
|
261
290
|
:version => VERSION
|
262
291
|
}
|
263
292
|
}
|
264
|
-
|
293
|
+
|
265
294
|
if defined?(SecureRandom) and SecureRandom.respond_to?(:uuid)
|
266
295
|
data[:uuid] = SecureRandom.uuid
|
267
296
|
end
|
268
|
-
|
297
|
+
|
269
298
|
data
|
270
299
|
end
|
271
300
|
|
272
301
|
def server_data
|
273
302
|
config = configuration
|
274
|
-
|
303
|
+
|
275
304
|
data = {
|
276
305
|
:host => Socket.gethostname
|
277
306
|
}
|
278
307
|
data[:root] = config.root.to_s if config.root
|
279
308
|
data[:branch] = config.branch if config.branch
|
280
|
-
|
309
|
+
|
281
310
|
data
|
282
311
|
end
|
283
|
-
|
312
|
+
|
284
313
|
def default_async_handler(payload)
|
285
314
|
if defined?(GirlFriday)
|
286
315
|
unless @queue
|
@@ -288,7 +317,7 @@ module Ratchetio
|
|
288
317
|
process_payload(payload)
|
289
318
|
end
|
290
319
|
end
|
291
|
-
|
320
|
+
|
292
321
|
@queue.push(payload)
|
293
322
|
else
|
294
323
|
logger.warn '[Ratchet.io] girl_friday not found to handle async call, falling back to Thread'
|
@@ -3,7 +3,7 @@ class HomeController < ApplicationController
|
|
3
3
|
@users = User.all
|
4
4
|
|
5
5
|
Ratchetio.report_message("Test message from controller with no data", "debug")
|
6
|
-
Ratchetio.report_message("Test message from controller with extra data", "debug",
|
6
|
+
Ratchetio.report_message("Test message from controller with extra data", "debug",
|
7
7
|
:foo => "bar", :num_users => @users.length)
|
8
8
|
end
|
9
9
|
|
data/spec/ratchetio_spec.rb
CHANGED
@@ -10,14 +10,14 @@ describe Ratchetio do
|
|
10
10
|
Ratchetio.configure do |config|
|
11
11
|
config.logger = logger_mock
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
begin
|
15
15
|
foo = bar
|
16
16
|
rescue => e
|
17
17
|
@exception = e
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
let(:logger_mock) { double("Rails.logger").as_null_object }
|
22
22
|
|
23
23
|
it 'should report exceptions without person or request data' do
|
@@ -30,9 +30,9 @@ describe Ratchetio do
|
|
30
30
|
Ratchetio.configure do |config|
|
31
31
|
config.enabled = false
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
Ratchetio.report_exception(@exception)
|
35
|
-
|
35
|
+
|
36
36
|
Ratchetio.configure do |config|
|
37
37
|
config.enabled = true
|
38
38
|
end
|
@@ -66,14 +66,30 @@ describe Ratchetio do
|
|
66
66
|
logger_mock.should_not_receive(:info)
|
67
67
|
logger_mock.should_not_receive(:warn)
|
68
68
|
logger_mock.should_not_receive(:error)
|
69
|
-
|
69
|
+
|
70
70
|
Ratchetio.report_exception(@exception)
|
71
|
-
|
71
|
+
|
72
72
|
Ratchetio.configure do |config|
|
73
73
|
config.exception_level_filters = saved_filters
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
it 'should not report exceptions when silenced' do
|
78
|
+
Ratchetio.should_not_receive :schedule_payload
|
79
|
+
|
80
|
+
begin
|
81
|
+
test_var = 1
|
82
|
+
Ratchetio.silenced do
|
83
|
+
test_var = 2
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
rescue => e
|
87
|
+
Ratchetio.report_exception(e)
|
88
|
+
end
|
89
|
+
|
90
|
+
test_var.should == 2
|
91
|
+
end
|
92
|
+
|
77
93
|
it 'should report exception objects with no backtrace' do
|
78
94
|
payload = nil
|
79
95
|
Ratchetio.stub(:schedule_payload) do |*args|
|
@@ -93,7 +109,7 @@ describe Ratchetio do
|
|
93
109
|
end
|
94
110
|
end
|
95
111
|
end
|
96
|
-
|
112
|
+
|
97
113
|
context 'report_message' do
|
98
114
|
before(:each) do
|
99
115
|
configure
|
@@ -101,7 +117,7 @@ describe Ratchetio do
|
|
101
117
|
config.logger = logger_mock
|
102
118
|
end
|
103
119
|
end
|
104
|
-
|
120
|
+
|
105
121
|
let(:logger_mock) { double("Rails.logger").as_null_object }
|
106
122
|
|
107
123
|
it 'should report simple messages' do
|
@@ -115,9 +131,9 @@ describe Ratchetio do
|
|
115
131
|
Ratchetio.configure do |config|
|
116
132
|
config.enabled = false
|
117
133
|
end
|
118
|
-
|
134
|
+
|
119
135
|
Ratchetio.report_message("Test message that should be ignored")
|
120
|
-
|
136
|
+
|
121
137
|
Ratchetio.configure do |config|
|
122
138
|
config.enabled = true
|
123
139
|
end
|
@@ -145,7 +161,7 @@ describe Ratchetio do
|
|
145
161
|
end
|
146
162
|
end
|
147
163
|
end
|
148
|
-
|
164
|
+
|
149
165
|
context 'payload_destination' do
|
150
166
|
before(:each) do
|
151
167
|
configure
|
@@ -153,83 +169,84 @@ describe Ratchetio do
|
|
153
169
|
config.logger = logger_mock
|
154
170
|
config.filepath = 'test.ratchet'
|
155
171
|
end
|
156
|
-
|
172
|
+
|
157
173
|
begin
|
158
174
|
foo = bar
|
159
175
|
rescue => e
|
160
176
|
@exception = e
|
161
177
|
end
|
162
178
|
end
|
163
|
-
|
179
|
+
|
164
180
|
let(:logger_mock) { double("Rails.logger").as_null_object }
|
165
|
-
|
181
|
+
|
166
182
|
it 'should send the payload over the network by default' do
|
167
183
|
logger_mock.should_not_receive(:info).with('[Ratchet.io] Writing payload to file')
|
168
184
|
logger_mock.should_receive(:info).with('[Ratchet.io] Sending payload')
|
169
185
|
logger_mock.should_receive(:info).with('[Ratchet.io] Success')
|
170
186
|
Ratchetio.report_exception(@exception)
|
171
187
|
end
|
172
|
-
|
188
|
+
|
173
189
|
it 'should save the payload to a file if set' do
|
174
190
|
logger_mock.should_not_receive(:info).with('[Ratchet.io] Sending payload')
|
175
191
|
logger_mock.should_receive(:info).with('[Ratchet.io] Writing payload to file')
|
176
192
|
logger_mock.should_receive(:info).with('[Ratchet.io] Success')
|
177
|
-
|
193
|
+
|
178
194
|
filepath = ''
|
179
|
-
|
195
|
+
|
180
196
|
Ratchetio.configure do |config|
|
181
197
|
config.write_to_file = true
|
182
198
|
filepath = config.filepath
|
183
199
|
end
|
184
|
-
|
200
|
+
|
185
201
|
Ratchetio.report_exception(@exception)
|
186
|
-
|
202
|
+
|
187
203
|
File.exist?(filepath).should == true
|
188
204
|
File.read(filepath).should include test_access_token
|
189
205
|
File.delete(filepath)
|
190
|
-
|
206
|
+
|
191
207
|
Ratchetio.configure do |config|
|
192
208
|
config.write_to_file = false
|
193
209
|
end
|
194
210
|
end
|
195
211
|
end
|
196
|
-
|
212
|
+
|
197
213
|
context 'asynchronous_handling' do
|
198
214
|
before(:each) do
|
199
215
|
configure
|
200
216
|
Ratchetio.configure do |config|
|
201
217
|
config.logger = logger_mock
|
202
218
|
end
|
203
|
-
|
219
|
+
|
204
220
|
begin
|
205
221
|
foo = bar
|
206
222
|
rescue => e
|
207
223
|
@exception = e
|
208
224
|
end
|
209
225
|
end
|
210
|
-
|
226
|
+
|
211
227
|
let(:logger_mock) { double("Rails.logger").as_null_object }
|
212
|
-
|
228
|
+
|
213
229
|
it 'should send the payload using the default asynchronous handler girl_friday' do
|
214
230
|
logger_mock.should_receive(:info).with('[Ratchet.io] Success')
|
215
|
-
|
231
|
+
|
216
232
|
Ratchetio.configure do |config|
|
217
233
|
config.use_async = true
|
218
234
|
GirlFriday::WorkQueue::immediate!
|
219
235
|
end
|
220
|
-
|
236
|
+
|
221
237
|
Ratchetio.report_exception(@exception)
|
222
|
-
|
238
|
+
|
223
239
|
Ratchetio.configure do |config|
|
224
240
|
config.use_async = false
|
225
241
|
GirlFriday::WorkQueue::queue!
|
226
242
|
end
|
227
243
|
end
|
228
|
-
|
244
|
+
|
229
245
|
it 'should send the payload using a user-supplied asynchronous handler' do
|
230
246
|
logger_mock.should_receive(:info).with('Custom async handler called')
|
247
|
+
logger_mock.should_receive(:info).with('[Ratchet.io] Sending payload')
|
231
248
|
logger_mock.should_receive(:info).with('[Ratchet.io] Success')
|
232
|
-
|
249
|
+
|
233
250
|
Ratchetio.configure do |config|
|
234
251
|
config.use_async = true
|
235
252
|
config.async_handler = Proc.new { |payload|
|
@@ -237,9 +254,9 @@ describe Ratchetio do
|
|
237
254
|
Ratchetio.process_payload(payload)
|
238
255
|
}
|
239
256
|
end
|
240
|
-
|
257
|
+
|
241
258
|
Ratchetio.report_exception(@exception)
|
242
|
-
|
259
|
+
|
243
260
|
Ratchetio.configure do |config|
|
244
261
|
config.use_async = false
|
245
262
|
config.async_handler = Ratchetio.method(:default_async_handler)
|
@@ -264,16 +281,16 @@ describe Ratchetio do
|
|
264
281
|
user_id = 123
|
265
282
|
name = "Tester"
|
266
283
|
|
267
|
-
data = Ratchetio.send(:message_data, @message_body, 'info',
|
284
|
+
data = Ratchetio.send(:message_data, @message_body, 'info',
|
268
285
|
:user_id => user_id, :name => name)
|
269
|
-
|
286
|
+
|
270
287
|
message = data[:body][:message]
|
271
288
|
message[:body].should == @message_body
|
272
289
|
message[:user_id].should == user_id
|
273
290
|
message[:name].should == name
|
274
291
|
end
|
275
292
|
end
|
276
|
-
|
293
|
+
|
277
294
|
context 'exception_data' do
|
278
295
|
before(:each) do
|
279
296
|
configure
|
@@ -283,7 +300,7 @@ describe Ratchetio do
|
|
283
300
|
@exception = e
|
284
301
|
end
|
285
302
|
end
|
286
|
-
|
303
|
+
|
287
304
|
it 'should accept force_level' do
|
288
305
|
level = 'critical'
|
289
306
|
data = Ratchetio.send(:exception_data, @exception, level)
|
@@ -292,11 +309,11 @@ describe Ratchetio do
|
|
292
309
|
|
293
310
|
it 'should build valid exception data' do
|
294
311
|
data = Ratchetio.send(:exception_data, @exception)
|
295
|
-
|
312
|
+
|
296
313
|
data[:level].should_not be_nil
|
297
|
-
|
314
|
+
|
298
315
|
trace = data[:body][:trace]
|
299
|
-
|
316
|
+
|
300
317
|
frames = trace[:frames]
|
301
318
|
frames.should be_a_kind_of(Array)
|
302
319
|
frames.each do |frame|
|
@@ -306,14 +323,14 @@ describe Ratchetio do
|
|
306
323
|
frame[:method].should be_a_kind_of(String)
|
307
324
|
end
|
308
325
|
end
|
309
|
-
|
326
|
+
|
310
327
|
# should be NameError, but can be NoMethodError sometimes on rubinius 1.8
|
311
328
|
# http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/
|
312
329
|
trace[:exception][:class].should match(/^(NameError|NoMethodError)$/)
|
313
330
|
trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
|
314
331
|
end
|
315
332
|
end
|
316
|
-
|
333
|
+
|
317
334
|
context 'logger' do
|
318
335
|
before(:each) do
|
319
336
|
reset_configuration
|
@@ -340,7 +357,7 @@ describe Ratchetio do
|
|
340
357
|
reset_configuration
|
341
358
|
end
|
342
359
|
end
|
343
|
-
|
360
|
+
|
344
361
|
context 'build_payload' do
|
345
362
|
it 'should build valid json' do
|
346
363
|
json = Ratchetio.send(:build_payload, {:foo => {:bar => "baz"}})
|
@@ -357,7 +374,7 @@ describe Ratchetio do
|
|
357
374
|
it 'should have the correct notifier name' do
|
358
375
|
Ratchetio.send(:base_data)[:notifier][:name].should == 'ratchetio-gem'
|
359
376
|
end
|
360
|
-
|
377
|
+
|
361
378
|
it 'should have the correct notifier version' do
|
362
379
|
Ratchetio.send(:base_data)[:notifier][:version].should == Ratchetio::VERSION
|
363
380
|
end
|