rollbar 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +143 -71
- data/UPGRADING.md +45 -0
- data/lib/rollbar.rb +470 -374
- data/lib/rollbar/active_record_extension.rb +1 -1
- data/lib/rollbar/configuration.rb +17 -0
- data/lib/rollbar/core_ext/thread.rb +9 -0
- data/lib/rollbar/exception_reporter.rb +4 -5
- data/lib/rollbar/logger_proxy.rb +32 -0
- data/lib/rollbar/middleware/rack/builder.rb +22 -4
- data/lib/rollbar/middleware/rails/rollbar.rb +62 -0
- data/lib/rollbar/middleware/rails/show_exceptions.rb +3 -5
- data/lib/rollbar/middleware/sinatra.rb +21 -5
- data/lib/rollbar/railtie.rb +18 -15
- data/lib/rollbar/request_data_extractor.rb +19 -9
- data/lib/rollbar/util.rb +39 -0
- data/lib/rollbar/version.rb +1 -1
- data/spec/controllers/home_controller_spec.rb +119 -154
- data/spec/dummyapp/app/controllers/home_controller.rb +16 -6
- data/spec/dummyapp/config/routes.rb +1 -0
- data/spec/rollbar/logger_proxy_spec.rb +35 -0
- data/spec/rollbar/middleware/rack/builder_spec.rb +61 -0
- data/spec/rollbar/middleware/sinatra_spec.rb +83 -5
- data/spec/rollbar_bc_spec.rb +388 -0
- data/spec/rollbar_spec.rb +940 -430
- data/spec/spec_helper.rb +1 -0
- metadata +12 -3
- data/lib/rollbar/middleware/rails/rollbar_request_store.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 850b8631306eb9e7c4e7379f869f573d74202b18
|
4
|
+
data.tar.gz: 10bbd67bc34a4635d5455b66c468bc3a4c65ce24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49809c4c002ff8a03d78b3c2b785bbf124ea754f4f54d668bf17bce21ab3bd9298fe9a15a09da2d50ba75b4ff7a6a03b03b601c1400aba6f2073c58128f49c4f
|
7
|
+
data.tar.gz: 204ec3d976719a22aa6333347d623ba17723d8574c2ab1c3b815f88631ebc996d3c4426619bbd8c8ddd88d34bab8a5a026cb9de0ed7f64d5c1202fca2d3d9408
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
**1.2.0**
|
4
|
+
- Added new, much nicer interface for sending exceptions and messages to Rollbar. This is a backwards-compatible release: the old interface (`report_message`, `report_exception`, `report_message_with_request`) is deprecated but will continue to work at least until 2.0.
|
5
|
+
|
6
|
+
See the docs for [basic](https://github.com/rollbar/rollbar-gem#caught-exceptions-and-messages) and [advanced](https://github.com/rollbar/rollbar-gem#advanced-usage) usage for a guide to the new interface. If you've used [rollbar.js](https://github.com/rollbar/rollbar.js), it will be familiar.
|
7
|
+
|
3
8
|
**1.1.0**
|
9
|
+
- Support nested exceptions for Ruby 2.1. See [#136](https://github.com/rollbar/rollbar-gem/pull/136). NOTE: for exceptions that have causes, this will change how they are grouped in Rollbar. If you have custom grouping rules, they will need to be updated to replace `body.trace.exception` with `body.trace_chain[0].exception` to maintain the same behavior for these exceptions.
|
4
10
|
- New feature: `failover_handlers`. You can specify a list of async handlers, which will be tried in sequence upon failure. See [#135](https://github.com/rollbar/rollbar-gem/pull/135).
|
5
|
-
- Support nested exceptions for Ruby 2.1. See [#136](https://github.com/rollbar/rollbar-gem/pull/136)
|
6
11
|
- Fix handling of utf8 sequences in payload symbols. See [#131](https://github.com/rollbar/rollbar-gem/pull/131). Thanks [@kroky](https://github.com/kroky) for the fix and [@jondeandres](https://github.com/jondeandres) for reviewing.
|
7
12
|
- Fix logic bugs in assignments for `scrub_fields` and `scrub_headers`. See [#137](https://github.com/rollbar/rollbar-gem/pull/137)
|
8
13
|
|
data/README.md
CHANGED
@@ -9,21 +9,19 @@ Ruby gem for reporting exceptions, errors, and log messages to [Rollbar](https:/
|
|
9
9
|
|
10
10
|
Add this line to your application's Gemfile:
|
11
11
|
|
12
|
-
gem 'rollbar', '~> 1.
|
12
|
+
gem 'rollbar', '~> 1.2.0'
|
13
13
|
|
14
14
|
And then execute:
|
15
15
|
|
16
16
|
```bash
|
17
17
|
$ bundle install
|
18
|
-
|
19
|
-
|
20
|
-
Or install it yourself as:
|
21
|
-
|
22
|
-
```bash
|
18
|
+
# Or if you don't use bundler:
|
23
19
|
$ gem install rollbar
|
24
20
|
```
|
25
21
|
|
26
|
-
|
22
|
+
### If using Rails
|
23
|
+
|
24
|
+
Run the following command from your Rails root:
|
27
25
|
|
28
26
|
```bash
|
29
27
|
$ rails generate rollbar POST_SERVER_ITEM_ACCESS_TOKEN
|
@@ -32,22 +30,20 @@ $ rails generate rollbar POST_SERVER_ITEM_ACCESS_TOKEN
|
|
32
30
|
<!-- RemoveNextIfProject -->
|
33
31
|
Be sure to replace ```POST_SERVER_ITEM_ACCESS_TOKEN``` with your project's ```post_server_item``` access token, which you can find in the Rollbar.com interface.
|
34
32
|
|
33
|
+
That's all you need to use Rollbar with Rails.
|
35
34
|
|
36
35
|
That will create the file ```config/initializers/rollbar.rb```, which holds the configuration values (currently just your access token).
|
37
36
|
|
38
|
-
If you want to store your access token outside of your repo, run the same command without arguments:
|
37
|
+
If you want to store your access token outside of your repo, run the same command without arguments, and create an environment variable ```ROLLBAR_ACCESS_TOKEN``` that holds your server-side access token:
|
39
38
|
|
40
39
|
```bash
|
41
40
|
$ rails generate rollbar
|
42
|
-
```
|
43
|
-
|
44
|
-
Then, create an environment variable ```ROLLBAR_ACCESS_TOKEN``` and set it to your server-side access token.
|
45
|
-
|
46
|
-
```bash
|
47
41
|
$ export ROLLBAR_ACCESS_TOKEN=POST_SERVER_ITEM_ACCESS_TOKEN
|
48
42
|
```
|
49
43
|
|
50
|
-
|
44
|
+
For Heroku users:
|
45
|
+
|
46
|
+
If you're on Heroku, you can store the access token in your Heroku config:
|
51
47
|
|
52
48
|
```bash
|
53
49
|
$ heroku config:add ROLLBAR_ACCESS_TOKEN=POST_SERVER_ITEM_ACCESS_TOKEN
|
@@ -55,6 +51,22 @@ $ heroku config:add ROLLBAR_ACCESS_TOKEN=POST_SERVER_ITEM_ACCESS_TOKEN
|
|
55
51
|
|
56
52
|
That's all you need to use Rollbar with Rails.
|
57
53
|
|
54
|
+
### If not using Rails
|
55
|
+
|
56
|
+
Be sure to initialize Rollbar with your access token somewhere during startup:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
Rollbar.configure do |config|
|
60
|
+
config.access_token = POST_SERVER_ITEM_ACCESS_TOKEN
|
61
|
+
# other configuration settings
|
62
|
+
# ...
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
<!-- RemoveNextIfProject -->
|
68
|
+
Be sure to replace ```POST_SERVER_ITEM_ACCESS_TOKEN``` with your project's ```post_server_item``` access token, which you can find in the Rollbar.com interface.
|
69
|
+
|
58
70
|
## Test your installation
|
59
71
|
|
60
72
|
To confirm that it worked, run:
|
@@ -65,7 +77,50 @@ $ rake rollbar:test
|
|
65
77
|
|
66
78
|
This will raise an exception within a test request; if it works, you'll see a stacktrace in the console, and the exception will appear in the Rollbar dashboard.
|
67
79
|
|
68
|
-
##
|
80
|
+
## Usage
|
81
|
+
|
82
|
+
### Uncaught exceptions
|
83
|
+
|
84
|
+
Uncaught exceptions in Rails controllers will be automatically reported to Rollbar.
|
85
|
+
|
86
|
+
### Caught exceptions and messages
|
87
|
+
|
88
|
+
You can use one of `Rollbar.log(level, ...)`, `Rollbar.debug()`, `Rollbar.info()`, `Rollbar.warning()`, `Rollbar.error()` and `Rollbar.critical()` to report exceptions and messages.
|
89
|
+
|
90
|
+
The methods take in any number of arguments, but the last exception is used as the reported exception, the last string is used as the message/description, and the last hash is used as the extra data.
|
91
|
+
|
92
|
+
For example:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
begin
|
96
|
+
result = user_info[:key1][:key2][:key3]
|
97
|
+
rescue NoMethodError => e
|
98
|
+
# simple exception report (level can be 'debug', 'info', 'warning', 'error' and 'critical')
|
99
|
+
Rollbar.log('error', e)
|
100
|
+
|
101
|
+
# same functionality as above
|
102
|
+
Rollbar.error(e)
|
103
|
+
|
104
|
+
# with a description
|
105
|
+
Rollbar.error(e, 'The user info hash doesn\'t contain the correct data')
|
106
|
+
|
107
|
+
# with extra data giving more insight about the exception
|
108
|
+
Rollbar.error(e, :user_info => user_info, :job_id => job_id)
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
You can also log individual messages:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
Rollbar.warning('Unexpected input')
|
116
|
+
|
117
|
+
# can also include extra data
|
118
|
+
Rollbar.info("Login successful", :username => @username)
|
119
|
+
|
120
|
+
Rollbar.log('debug', 'Settings saved', :account_id => account.id)
|
121
|
+
```
|
122
|
+
|
123
|
+
### Reporting form validation errors
|
69
124
|
|
70
125
|
To get form validation errors automatically reported to Rollbar just add the following ```after_validation``` callback to your models:
|
71
126
|
|
@@ -73,59 +128,97 @@ To get form validation errors automatically reported to Rollbar just add the fol
|
|
73
128
|
after_validation :report_validation_errors_to_rollbar
|
74
129
|
```
|
75
130
|
|
76
|
-
|
131
|
+
### Advanced usage
|
132
|
+
|
133
|
+
You can use `Rollbar.scope()` to copy a notifier instance and customize the payload data for one-off reporting. The hash argument to `scope()` will be merged into the copied notifier's "payload options", a hash that will be merged into the final payload just before it is reported to Rollbar.
|
77
134
|
|
78
|
-
|
135
|
+
For example:
|
79
136
|
|
80
137
|
```ruby
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
138
|
+
while job
|
139
|
+
user = job.user
|
140
|
+
|
141
|
+
# Overwrites any existing person data
|
142
|
+
notifier = Rollbar.scope({
|
143
|
+
:person => {:id => user.id, :username => user.username, :email => user.email}
|
144
|
+
})
|
145
|
+
|
146
|
+
begin
|
147
|
+
job.do_work
|
148
|
+
rescue => e
|
149
|
+
# Sends a report with the above person data
|
150
|
+
notifier.critical(e)
|
151
|
+
end
|
152
|
+
|
153
|
+
job = next_job
|
85
154
|
end
|
155
|
+
|
156
|
+
# Wipe person data
|
157
|
+
notifier = notifier.scope({
|
158
|
+
:person => nil
|
159
|
+
})
|
160
|
+
|
161
|
+
# No associated person data
|
162
|
+
notifier.info('Jobs processed')
|
86
163
|
```
|
87
164
|
|
88
|
-
If you'
|
165
|
+
If you don't want to work with a new `Notifier` instance `#scoped` will do it for you:
|
89
166
|
|
90
167
|
```ruby
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
168
|
+
while job
|
169
|
+
user = job.user
|
170
|
+
|
171
|
+
# Overwrites any existing person data
|
172
|
+
scope = {
|
173
|
+
:person => {:id => user.id, :username => user.username, :email => user.email}
|
174
|
+
}
|
175
|
+
|
176
|
+
Rollbar.scoped(scope) do
|
177
|
+
begin
|
178
|
+
job.do_work
|
179
|
+
rescue => e
|
180
|
+
# Sends a report with the above person data
|
181
|
+
Rollbar.critical(e)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
job = next_job
|
95
186
|
end
|
96
187
|
```
|
97
188
|
|
98
|
-
|
189
|
+
## Person tracking
|
190
|
+
|
191
|
+
Rollbar will send information about the current user (called a "person" in Rollbar parlance) along with each error report, when available. This works by calling the ```current_user``` controller method. The return value should be an object with an ```id``` method and, optionally, ```username``` and ```email``` methods.
|
192
|
+
|
193
|
+
This will happen automatically for uncaught Rails exceptions and for any manual exception or log reporting done within a Rails request.
|
194
|
+
|
195
|
+
If the gem should call a controller method besides ```current_user```, add the following in ```config/initializers/rollbar.rb```:
|
99
196
|
|
100
197
|
```ruby
|
101
|
-
|
102
|
-
|
103
|
-
rescue Exception => e
|
104
|
-
# all levels: debug, info, warning, error, critical
|
105
|
-
Rollbar.report_exception(e, rollbar_request_data, rollbar_person_data, "warning")
|
198
|
+
Rollbar.configure do |config|
|
199
|
+
config.person_method = "my_current_user"
|
106
200
|
end
|
107
|
-
|
108
201
|
```
|
109
202
|
|
110
|
-
|
203
|
+
If the methods to extract the ```id```, ```username```, and ```email``` from the object returned by the ```person_method``` have other names, configure like so in ```config/initializers/rollbar.rb```:
|
111
204
|
|
112
205
|
```ruby
|
113
|
-
Rollbar.
|
206
|
+
Rollbar.configure do |config|
|
207
|
+
config.person_id_method = "user_id" # default is "id"
|
208
|
+
config.person_username_method = "user_name" # default is "username"
|
209
|
+
config.person_email_method = "email_address" # default is "email"
|
210
|
+
end
|
211
|
+
```
|
114
212
|
|
115
|
-
|
116
|
-
Rollbar.report_message("Login successful")
|
213
|
+
## Special note about reporting within a request
|
117
214
|
|
118
|
-
|
119
|
-
Rollbar.report_message("Login successful", "info", :username => @username)
|
215
|
+
The gem instantiates one `Notifier` instance on initialization, which will be the base notifier that is used for all reporting (via a `method_missing` proxy in the `Rollbar` module). Calling `Rollbar.configure()` will configure this base notifier that will be used globally in a ruby app.
|
120
216
|
|
121
|
-
#
|
122
|
-
Rollbar.report_message_with_request("Settings saved", "debug", rollbar_request_data,
|
123
|
-
rollbar_person_data, :account_id => account.id)
|
124
|
-
```
|
217
|
+
However, the Rails middleware will actually scope this base notifier for use within a request by storing it in thread-local storage (see [here](https://github.com/rollbar/rollbar-gem/blob/5f4e6135f0e61148672b0190c88767aa52e5cdb3/lib/rollbar/middleware/rails/rollbar.rb#L35-L39)). This is done to make any manual logging within a request automatically contain request and person data. Calling `Rollbar.configure()` therefore will only affect the notifier for the duration of the request, and not the base notifier used globally.
|
125
218
|
|
126
219
|
## Data sanitization (scrubbing)
|
127
220
|
|
128
|
-
By default, the notifier will "scrub" the following fields from
|
221
|
+
By default, the notifier will "scrub" the following fields from payloads before sending to Rollbar
|
129
222
|
|
130
223
|
- ```:passwd```
|
131
224
|
- ```:password```
|
@@ -155,34 +248,9 @@ And ```Rollbar.configuration.scrub_headers```:
|
|
155
248
|
Rollbar.configuration.scrub_headers |= ["X-Access-Token"]
|
156
249
|
```
|
157
250
|
|
158
|
-
|
159
|
-
## Person tracking
|
160
|
-
|
161
|
-
Rollbar will send information about the current user (called a "person" in Rollbar parlance) along with each error report, when available. This works by calling the ```current_user``` controller method. The return value should be an object with an ```id``` method and, optionally, ```username``` and ```email``` methods.
|
162
|
-
|
163
|
-
If the gem should call a controller method besides ```current_user```, add the following in ```config/initializers/rollbar.rb```:
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
config.person_method = "my_current_user"
|
167
|
-
```
|
168
|
-
|
169
|
-
If the methods to extract the ```id```, ```username```, and ```email``` from the object returned by the ```person_method``` have other names, configure like so in ```config/initializers/rollbar.rb```:
|
170
|
-
|
171
|
-
```ruby
|
172
|
-
config.person_id_method = "user_id" # default is "id"
|
173
|
-
config.person_username_method = "user_name" # default is "username"
|
174
|
-
config.person_email_method = "email_address" # default is "email"
|
175
|
-
```
|
176
|
-
|
177
|
-
### If using Rails and not ActiveRecord
|
178
|
-
|
179
|
-
By default, the `Rollbar::Middleware::Rails::RollbarRequestStore` middleware is inserted just before the `ActiveRecord::ConnectionAdapters::ConnectionManagement` middleware if `ActiveRecord` is defined. This middleware ensures that any database calls needed to grab person data are executed before connections are cleaned up in the `ConnectionManagement` middleware.
|
180
|
-
|
181
|
-
If you are not using `ActiveRecord`, make sure you include the `RollbarRequestStore` middleware before any middlewares that do similar connection clean up.
|
182
|
-
|
183
251
|
## Including additional runtime data
|
184
252
|
|
185
|
-
You can provide a
|
253
|
+
You can provide a callable that will be called for each exception or message report. ```custom_data_method``` should be a lambda that takes no arguments and returns a hash.
|
186
254
|
|
187
255
|
Add the following in ```config/initializers/rollbar.rb```:
|
188
256
|
|
@@ -196,7 +264,7 @@ This data will appear in the Occurrences tab and on the Occurrence Detail pages
|
|
196
264
|
|
197
265
|
## Exception level filters
|
198
266
|
|
199
|
-
By default, all exceptions
|
267
|
+
By default, all uncaught exceptions are reported at the "error" level, except for the following, which are reported at "warning" level:
|
200
268
|
|
201
269
|
- ```ActiveRecord::RecordNotFound```
|
202
270
|
- ```AbstractController::ActionNotFound```
|
@@ -427,6 +495,10 @@ Check out [resque-rollbar](https://github.com/dimko/resque-rollbar) for using Ro
|
|
427
495
|
|
428
496
|
Some users have reported problems with Zeus when ```rake``` was not explicitly included in their Gemfile. If the zeus server fails to start after installing the rollbar gem, try explicitly adding ```gem 'rake'``` to your ```Gemfile```. See [this thread](https://github.com/rollbar/rollbar-gem/issues/30) for more information.
|
429
497
|
|
498
|
+
## Backwards Compatibility
|
499
|
+
|
500
|
+
You can find upgrading notes in [UPGRADING.md](UPGRADING.md).
|
501
|
+
|
430
502
|
|
431
503
|
## Help / Support
|
432
504
|
|
data/UPGRADING.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Upgrading
|
2
|
+
|
3
|
+
## From 1.1.0 or lower to 1.2.0
|
4
|
+
|
5
|
+
The public interface has been rewritten entirely in 1.2.0 to be more versatile and in-line with the new interface established recently in rollbar.js. The main `#report_message` and `#report_exception` methods are now deprecated in favor of the new `#log`, `#debug` `#info`, `#warn`, `#error` and `#critical` methods.
|
6
|
+
|
7
|
+
The new methods will accept any number of arguments. The last string argument is used as a message/description, the last exception argument is used as the reported exception, and the last hash is used as the extra data (except for `log` which requires an additional level string as the first argument).
|
8
|
+
|
9
|
+
The old methods will still function properly but it is recommended to migrate to the new interface whenever possible. You can migrate simply by doing the following:
|
10
|
+
|
11
|
+
1. Replace all occurrences of `#report_exception` with `#error`, or `#log` with a custom level if set in your existing `#report_exception` call.
|
12
|
+
|
13
|
+
2. Replace all occurrences of `#report_message` and `#report_message_with_request` with the one of the logging methods `#debug` through `#critical`.
|
14
|
+
|
15
|
+
3. The argument order can stay the same.
|
16
|
+
|
17
|
+
If using a Rack application, `request_data` and `person_data` will not longer be required to be passed in when logging messages or exceptions. The Rack, Sinatra or Rails middleware is responsible to extract the data and pass it to Rollbar.
|
18
|
+
|
19
|
+
If **not** using any Rack application, then you will need to use the `#scope` or `#scoped` method to set this data manually:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
notifier = Rollbar.scope({
|
23
|
+
:request => rollbar_request_data,
|
24
|
+
:person => rollbar_person_data
|
25
|
+
})
|
26
|
+
|
27
|
+
# will contain request parameters and person data
|
28
|
+
notifier.warning('User submitted invalid form data')
|
29
|
+
```
|
30
|
+
|
31
|
+
The `#scoped`method allows to change the payload options for a specific code block. This is the method used by the Rack and Rails middlewares.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
scope = { :request => rollbar_request_data,
|
35
|
+
:person => rollbar_person_data
|
36
|
+
}
|
37
|
+
|
38
|
+
Rollbar.scoped(scope) do
|
39
|
+
begin
|
40
|
+
# code that will raise
|
41
|
+
rescue => e
|
42
|
+
Rollbar.error(e)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
data/lib/rollbar.rb
CHANGED
@@ -11,6 +11,7 @@ end
|
|
11
11
|
|
12
12
|
require 'rollbar/version'
|
13
13
|
require 'rollbar/configuration'
|
14
|
+
require 'rollbar/logger_proxy'
|
14
15
|
require 'rollbar/request_data_extractor'
|
15
16
|
require 'rollbar/exception_reporter'
|
16
17
|
require 'rollbar/active_record_extension' if defined?(ActiveRecord)
|
@@ -18,6 +19,7 @@ require 'rollbar/util'
|
|
18
19
|
require 'rollbar/railtie' if defined?(Rails)
|
19
20
|
require 'rollbar/delay/girl_friday'
|
20
21
|
require 'rollbar/delay/thread'
|
22
|
+
require 'rollbar/core_ext/thread'
|
21
23
|
|
22
24
|
unless ''.respond_to? :encode
|
23
25
|
require 'iconv'
|
@@ -25,8 +27,29 @@ end
|
|
25
27
|
|
26
28
|
module Rollbar
|
27
29
|
MAX_PAYLOAD_SIZE = 128 * 1024 #128kb
|
30
|
+
ATTACHMENT_CLASSES = %w[
|
31
|
+
ActionDispatch::Http::UploadedFile
|
32
|
+
Rack::Multipart::UploadedFile
|
33
|
+
].freeze
|
34
|
+
PUBLIC_NOTIFIER_METHODS = %w(debug info warn warning error critical log logger
|
35
|
+
process_payload scope send_failsafe log_info log_debug
|
36
|
+
log_warning log_error silenced)
|
37
|
+
|
38
|
+
class Notifier
|
39
|
+
attr_accessor :configuration
|
40
|
+
|
41
|
+
def initialize(parent_notifier = nil, payload_options = nil)
|
42
|
+
if parent_notifier
|
43
|
+
@configuration = parent_notifier.configuration.clone
|
44
|
+
|
45
|
+
if payload_options
|
46
|
+
Rollbar::Util.deep_merge(@configuration.payload_options, payload_options)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
@configuration = ::Rollbar::Configuration.new
|
50
|
+
end
|
51
|
+
end
|
28
52
|
|
29
|
-
class << self
|
30
53
|
attr_writer :configuration
|
31
54
|
attr_accessor :last_report
|
32
55
|
|
@@ -38,253 +61,131 @@ module Rollbar
|
|
38
61
|
yield(configuration)
|
39
62
|
end
|
40
63
|
|
41
|
-
# Configures the
|
42
|
-
#
|
43
|
-
# Call on app startup to set the `access_token` (required) and other config params.
|
44
|
-
# In a Rails app, this is called by `config/initializers/rollbar.rb` which is generated
|
45
|
-
# with `rails generate rollbar access-token-here`
|
46
|
-
#
|
47
|
-
# @example
|
48
|
-
# Rollbar.configure do |config|
|
49
|
-
# config.access_token = 'abcdefg'
|
50
|
-
# end
|
64
|
+
# Configures the notifier instance
|
51
65
|
def configure
|
52
|
-
# if configuration.enabled has not been set yet (is still 'nil'), set to true.
|
53
66
|
configuration.enabled = true if configuration.enabled.nil?
|
54
67
|
|
55
68
|
yield(configuration)
|
56
|
-
|
57
|
-
require_hooks
|
58
69
|
end
|
59
70
|
|
60
|
-
def
|
61
|
-
|
62
|
-
@configuration.enabled = true
|
63
|
-
yield(configuration)
|
71
|
+
def scope(options = {})
|
72
|
+
self.class.new(self, options)
|
64
73
|
end
|
65
74
|
|
66
|
-
def
|
67
|
-
|
75
|
+
def configure
|
76
|
+
yield(configuration)
|
68
77
|
end
|
69
78
|
|
70
|
-
#
|
79
|
+
# Turns off reporting for the given block.
|
71
80
|
#
|
72
|
-
# @
|
73
|
-
|
74
|
-
|
81
|
+
# @example
|
82
|
+
# Rollbar.silenced { raise }
|
83
|
+
#
|
84
|
+
# @yield Block which exceptions won't be reported.
|
85
|
+
def silenced
|
86
|
+
yield
|
87
|
+
rescue => e
|
88
|
+
e.instance_variable_set(:@_rollbar_do_not_report, true)
|
89
|
+
raise
|
75
90
|
end
|
76
91
|
|
77
|
-
#
|
92
|
+
# Sends a report to Rollbar.
|
93
|
+
#
|
94
|
+
# Accepts any number of arguments. The last String argument will become
|
95
|
+
# the message or description of the report. The last Exception argument
|
96
|
+
# will become the associated exception for the report. The last hash
|
97
|
+
# argument will be used as the extra data for the report.
|
78
98
|
#
|
79
99
|
# @example
|
80
100
|
# begin
|
81
101
|
# foo = bar
|
82
102
|
# rescue => e
|
83
|
-
# Rollbar.
|
103
|
+
# Rollbar.log(e)
|
84
104
|
# end
|
85
105
|
#
|
86
|
-
# @param exception [Exception] The exception object to report
|
87
|
-
# @param request_data [Hash] Data describing the request. Should be the result of calling
|
88
|
-
# `rollbar_request_data`.
|
89
|
-
# @param person_data [Hash] Data describing the affected person. Should be the result of calling
|
90
|
-
# `rollbar_person_data`
|
91
|
-
def report_exception(exception, request_data = nil, person_data = nil, level = nil)
|
92
|
-
if person_data
|
93
|
-
person_id = person_data[Rollbar.configuration.person_id_method.to_sym]
|
94
|
-
return 'ignored' if configuration.ignored_person_ids.include?(person_id)
|
95
|
-
end
|
96
|
-
|
97
|
-
return 'disabled' unless configuration.enabled
|
98
|
-
return 'ignored' if ignored?(exception)
|
99
|
-
|
100
|
-
data = exception_data(exception, level ? level : filtered_level(exception))
|
101
|
-
|
102
|
-
attach_request_data(data, request_data) if request_data
|
103
|
-
data[:person] = person_data if person_data
|
104
|
-
|
105
|
-
@last_report = data
|
106
|
-
|
107
|
-
payload = build_payload(data)
|
108
|
-
schedule_payload(payload)
|
109
|
-
log_instance_link(data)
|
110
|
-
data
|
111
|
-
rescue Exception => e
|
112
|
-
report_internal_error(e)
|
113
|
-
'error'
|
114
|
-
end
|
115
|
-
|
116
|
-
# Reports an arbitrary message to Rollbar
|
117
|
-
#
|
118
106
|
# @example
|
119
|
-
# Rollbar.
|
120
|
-
#
|
121
|
-
# @param message [String] The message body. This will be used to identify the message within
|
122
|
-
# Rollbar. For best results, avoid putting variables in the message body; pass them as
|
123
|
-
# `extra_data` instead.
|
124
|
-
# @param level [String] The level. One of: 'critical', 'error', 'warning', 'info', 'debug'
|
125
|
-
# @param extra_data [Hash] Additional data to include alongside the body. Don't use 'body' as
|
126
|
-
# it is reserved.
|
127
|
-
def report_message(message, level = 'info', extra_data = {})
|
128
|
-
return 'disabled' unless configuration.enabled
|
129
|
-
|
130
|
-
data = message_data(message, level, extra_data)
|
131
|
-
|
132
|
-
@last_report = data
|
133
|
-
|
134
|
-
payload = build_payload(data)
|
135
|
-
schedule_payload(payload)
|
136
|
-
log_instance_link(data)
|
137
|
-
data
|
138
|
-
rescue Exception => e
|
139
|
-
report_internal_error(e)
|
140
|
-
'error'
|
141
|
-
end
|
142
|
-
|
143
|
-
# Reports an arbitrary message to Rollbar with request and person data
|
107
|
+
# Rollbar.log('This is a simple log message')
|
144
108
|
#
|
145
109
|
# @example
|
146
|
-
# Rollbar.
|
110
|
+
# Rollbar.log(e, 'This is a description of the exception')
|
147
111
|
#
|
148
|
-
|
149
|
-
# Rollbar. For best results, avoid putting variables in the message body; pass them as
|
150
|
-
# `extra_data` instead.
|
151
|
-
# @param level [String] The level. One of: 'critical', 'error', 'warning', 'info', 'debug'
|
152
|
-
# @param request_data [Hash] Data describing the request. Should be the result of calling
|
153
|
-
# `rollbar_request_data`.
|
154
|
-
# @param person_data [Hash] Data describing the affected person. Should be the result of calling
|
155
|
-
# `rollbar_person_data`
|
156
|
-
# @param extra_data [Hash] Additional data to include alongside the body. Don't use 'body' as
|
157
|
-
# it is reserved.
|
158
|
-
def report_message_with_request(message, level = 'info', request_data = nil, person_data = nil, extra_data = {})
|
112
|
+
def log(level, *args)
|
159
113
|
return 'disabled' unless configuration.enabled
|
160
114
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
115
|
+
message = nil
|
116
|
+
exception = nil
|
117
|
+
extra = nil
|
118
|
+
|
119
|
+
args.each do |arg|
|
120
|
+
if arg.is_a?(String)
|
121
|
+
message = arg
|
122
|
+
elsif arg.is_a?(Exception)
|
123
|
+
exception = arg
|
124
|
+
elsif arg.is_a?(Hash)
|
125
|
+
extra = arg
|
126
|
+
end
|
127
|
+
end
|
167
128
|
|
168
|
-
|
169
|
-
schedule_payload(payload)
|
170
|
-
log_instance_link(data)
|
171
|
-
data
|
172
|
-
rescue => e
|
173
|
-
report_internal_error(e)
|
174
|
-
'error'
|
175
|
-
end
|
129
|
+
return 'ignored' if ignored?(exception)
|
176
130
|
|
177
|
-
# Turns off reporting for the given block.
|
178
|
-
#
|
179
|
-
# @example
|
180
|
-
# Rollbar.silenced { raise }
|
181
|
-
#
|
182
|
-
# @yield Block which exceptions won't be reported.
|
183
|
-
def silenced
|
184
131
|
begin
|
185
|
-
|
186
|
-
rescue => e
|
187
|
-
e
|
188
|
-
|
132
|
+
report(level, message, exception, extra)
|
133
|
+
rescue Exception => e
|
134
|
+
report_internal_error(e)
|
135
|
+
'error'
|
189
136
|
end
|
190
137
|
end
|
191
138
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
write_payload(payload)
|
196
|
-
else
|
197
|
-
send_payload(payload)
|
198
|
-
end
|
199
|
-
rescue => e
|
200
|
-
log_error "[Rollbar] Error processing payload: #{e}"
|
201
|
-
end
|
139
|
+
# See log() above
|
140
|
+
def debug(*args)
|
141
|
+
log('debug', *args)
|
202
142
|
end
|
203
143
|
|
204
|
-
#
|
205
|
-
def
|
206
|
-
|
207
|
-
logger.error message
|
208
|
-
rescue => e
|
209
|
-
puts "[Rollbar] Error logging error:"
|
210
|
-
puts "[Rollbar] #{message}"
|
211
|
-
end
|
144
|
+
# See log() above
|
145
|
+
def info(*args)
|
146
|
+
log('info', *args)
|
212
147
|
end
|
213
148
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
rescue => e
|
218
|
-
puts "[Rollbar] Error logging info:"
|
219
|
-
puts "[Rollbar] #{message}"
|
220
|
-
end
|
149
|
+
# See log() above
|
150
|
+
def warn(*args)
|
151
|
+
log('warning', *args)
|
221
152
|
end
|
222
153
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
rescue => e
|
227
|
-
puts "[Rollbar] Error logging warning:"
|
228
|
-
puts "[Rollbar] #{message}"
|
229
|
-
end
|
154
|
+
# See log() above
|
155
|
+
def warning(*args)
|
156
|
+
log('warning', *args)
|
230
157
|
end
|
231
158
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
rescue => e
|
236
|
-
puts "[Rollbar] Error logging debug"
|
237
|
-
puts "[Rollbar] #{message}"
|
238
|
-
end
|
159
|
+
# See log() above
|
160
|
+
def error(*args)
|
161
|
+
log('error', *args)
|
239
162
|
end
|
240
163
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
Rollbar::Delay::Thread
|
164
|
+
# See log() above
|
165
|
+
def critical(*args)
|
166
|
+
log('critical', *args)
|
245
167
|
end
|
246
168
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
payload[:context] = "#{request_data[:route][:controller]}" + '#' + "#{request_data[:route][:action]}"
|
169
|
+
def process_payload(payload)
|
170
|
+
if configuration.write_to_file
|
171
|
+
if configuration.use_async
|
172
|
+
@file_semaphore.synchronize {
|
173
|
+
write_payload(payload)
|
174
|
+
}
|
175
|
+
else
|
176
|
+
write_payload(payload)
|
256
177
|
end
|
178
|
+
else
|
179
|
+
send_payload(payload)
|
257
180
|
end
|
258
|
-
|
259
|
-
request_data[:env].reject!{|k, v| v.is_a?(IO) } if request_data[:env]
|
260
|
-
payload[:request] = request_data
|
261
|
-
end
|
262
|
-
|
263
|
-
def require_hooks()
|
264
|
-
if defined?(Delayed) && defined?(Delayed::Worker) && configuration.delayed_job_enabled
|
265
|
-
require 'rollbar/delayed_job'
|
266
|
-
Rollbar::Delayed::wrap_worker
|
267
|
-
end
|
268
|
-
|
269
|
-
require 'rollbar/sidekiq' if defined?(Sidekiq)
|
270
|
-
require 'rollbar/goalie' if defined?(Goalie)
|
271
|
-
require 'rollbar/rack' if defined?(Rack)
|
272
|
-
require 'rollbar/rake' if defined?(Rake)
|
273
|
-
require 'rollbar/better_errors' if defined?(BetterErrors)
|
274
181
|
end
|
275
182
|
|
276
|
-
|
277
|
-
log_info "[Rollbar] Details: #{configuration.web_base}/instance/uuid?uuid=#{data[:uuid]} (only available if report was successful)"
|
278
|
-
end
|
183
|
+
private
|
279
184
|
|
280
185
|
def ignored?(exception)
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
if exception.instance_variable_get(:@_rollbar_do_not_report)
|
286
|
-
return true
|
287
|
-
end
|
186
|
+
return false unless exception
|
187
|
+
return true if filtered_level(exception) == 'ignore'
|
188
|
+
return true if exception.instance_variable_get(:@_rollbar_do_not_report)
|
288
189
|
|
289
190
|
false
|
290
191
|
end
|
@@ -298,53 +199,114 @@ module Rollbar
|
|
298
199
|
end
|
299
200
|
end
|
300
201
|
|
301
|
-
def
|
302
|
-
|
202
|
+
def report(level, message, exception, extra)
|
203
|
+
unless message || exception || extra
|
204
|
+
log_error "[Rollbar] Tried to send a report with no message, exception or extra data."
|
205
|
+
return 'error'
|
206
|
+
end
|
303
207
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
208
|
+
payload = build_payload(level, message, exception, extra)
|
209
|
+
data = payload['data']
|
210
|
+
evaluate_payload(data)
|
211
|
+
|
212
|
+
if data[:person]
|
213
|
+
person_id = data[:person][configuration.person_id_method.to_sym]
|
214
|
+
return 'ignored' if configuration.ignored_person_ids.include?(person_id)
|
215
|
+
end
|
216
|
+
|
217
|
+
schedule_payload(payload)
|
218
|
+
|
219
|
+
log_instance_link(data)
|
220
|
+
|
221
|
+
Rollbar.last_report = data
|
311
222
|
|
312
223
|
data
|
313
224
|
end
|
314
225
|
|
315
|
-
|
316
|
-
|
226
|
+
# Reports an internal error in the Rollbar library. This will be reported within the configured
|
227
|
+
# Rollbar project. We'll first attempt to provide a report including the exception traceback.
|
228
|
+
# If that fails, we'll fall back to a more static failsafe response.
|
229
|
+
def report_internal_error(exception)
|
230
|
+
log_error "[Rollbar] Reporting internal error encountered while sending data to Rollbar."
|
317
231
|
|
318
|
-
|
232
|
+
begin
|
233
|
+
payload = build_payload('error', nil, exception, {:internal => true})
|
234
|
+
rescue => e
|
235
|
+
send_failsafe("build_payload in exception_data", e)
|
236
|
+
return
|
237
|
+
end
|
319
238
|
|
320
|
-
|
239
|
+
begin
|
240
|
+
process_payload(payload)
|
241
|
+
rescue => e
|
242
|
+
send_failsafe("error in process_payload", e)
|
243
|
+
return
|
244
|
+
end
|
321
245
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
body = {
|
328
|
-
:trace => traces[0]
|
329
|
-
}
|
246
|
+
begin
|
247
|
+
log_instance_link(payload['data'])
|
248
|
+
rescue => e
|
249
|
+
send_failsafe("error logging instance link", e)
|
250
|
+
return
|
330
251
|
end
|
252
|
+
end
|
331
253
|
|
332
|
-
|
254
|
+
## Payload building functions
|
333
255
|
|
334
|
-
|
256
|
+
def build_payload(level, message, exception, extra)
|
257
|
+
environment = configuration.environment
|
258
|
+
environment = 'unspecified' if environment.nil? || environment.empty?
|
335
259
|
|
336
|
-
data
|
260
|
+
data = {
|
261
|
+
:timestamp => Time.now.to_i,
|
262
|
+
:environment => environment,
|
263
|
+
:level => level,
|
264
|
+
:language => 'ruby',
|
265
|
+
:framework => configuration.framework,
|
266
|
+
:server => server_data,
|
267
|
+
:notifier => {
|
268
|
+
:name => 'rollbar-gem',
|
269
|
+
:version => VERSION
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
data[:body] = build_payload_body(message, exception, extra)
|
274
|
+
data[:project_package_paths] = configuration.project_gem_paths if configuration.project_gem_paths
|
275
|
+
data[:code_version] = configuration.code_version if configuration.code_version
|
276
|
+
data[:uuid] = SecureRandom.uuid if defined?(SecureRandom) && SecureRandom.respond_to?(:uuid)
|
277
|
+
|
278
|
+
Rollbar::Util.deep_merge(data, configuration.payload_options)
|
279
|
+
|
280
|
+
{
|
281
|
+
'access_token' => configuration.access_token,
|
282
|
+
'data' => data
|
283
|
+
}
|
337
284
|
end
|
338
285
|
|
339
|
-
def
|
340
|
-
|
286
|
+
def build_payload_body(message, exception, extra)
|
287
|
+
unless configuration.custom_data_method.nil?
|
288
|
+
custom = Rollbar::Util.deep_copy(configuration.custom_data_method.call)
|
289
|
+
extra = Rollbar::Util.deep_merge(custom, extra || {})
|
290
|
+
end
|
341
291
|
|
342
|
-
|
343
|
-
|
344
|
-
|
292
|
+
if exception
|
293
|
+
build_payload_body_exception(message, exception, extra)
|
294
|
+
else
|
295
|
+
build_payload_body_message(message, extra)
|
345
296
|
end
|
297
|
+
end
|
346
298
|
|
347
|
-
|
299
|
+
def build_payload_body_exception(message, exception, extra)
|
300
|
+
traces = trace_chain(exception)
|
301
|
+
|
302
|
+
traces[0][:exception][:description] = message if message
|
303
|
+
traces[0][:extra] = extra if extra
|
304
|
+
|
305
|
+
if traces.size > 1
|
306
|
+
{ :trace_chain => traces }
|
307
|
+
elsif traces.size == 1
|
308
|
+
{ :trace => traces[0] }
|
309
|
+
end
|
348
310
|
end
|
349
311
|
|
350
312
|
def trace_data(exception)
|
@@ -374,37 +336,108 @@ module Rollbar
|
|
374
336
|
}
|
375
337
|
end
|
376
338
|
|
377
|
-
def
|
378
|
-
|
379
|
-
|
380
|
-
|
339
|
+
def trace_chain(exception)
|
340
|
+
traces = [trace_data(exception)]
|
341
|
+
|
342
|
+
while exception.respond_to?(:cause) && (cause = exception.cause)
|
343
|
+
traces << trace_data(cause)
|
344
|
+
exception = cause
|
381
345
|
end
|
382
|
-
|
346
|
+
|
347
|
+
traces
|
383
348
|
end
|
384
349
|
|
385
|
-
def
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
350
|
+
def build_payload_body_message(message, extra)
|
351
|
+
result = { :body => message || 'Empty message'}
|
352
|
+
result[:extra] = extra if extra
|
353
|
+
|
354
|
+
{ :message => result }
|
355
|
+
end
|
356
|
+
|
357
|
+
def server_data
|
358
|
+
data = {
|
359
|
+
:host => Socket.gethostname
|
360
|
+
}
|
361
|
+
data[:root] = configuration.root.to_s if configuration.root
|
362
|
+
data[:branch] = configuration.branch if configuration.branch
|
363
|
+
|
364
|
+
data
|
365
|
+
end
|
366
|
+
|
367
|
+
# Walks the entire payload and replaces callable values with
|
368
|
+
# their results
|
369
|
+
def evaluate_payload(payload)
|
370
|
+
evaluator = proc do |key, value|
|
371
|
+
result = value
|
372
|
+
|
373
|
+
if value.respond_to? :call
|
374
|
+
begin
|
375
|
+
result = value.call
|
376
|
+
rescue
|
377
|
+
log_error "[Rollbar] Error while evaluating callable in payload for key #{key}"
|
378
|
+
result = nil
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
result
|
392
383
|
end
|
384
|
+
|
385
|
+
Rollbar::Util.iterate_and_update_hash(payload, evaluator)
|
393
386
|
end
|
394
387
|
|
395
|
-
def
|
396
|
-
|
388
|
+
def enforce_valid_utf8(payload)
|
389
|
+
normalizer = lambda do |object|
|
390
|
+
is_symbol = object.is_a?(Symbol)
|
397
391
|
|
398
|
-
|
399
|
-
|
400
|
-
|
392
|
+
return object unless object == object.to_s || is_symbol
|
393
|
+
|
394
|
+
value = object.to_s
|
395
|
+
|
396
|
+
if value.respond_to? :encode
|
397
|
+
encoded_value = value.encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
|
398
|
+
else
|
399
|
+
encoded_value = ::Iconv.conv('UTF-8//IGNORE', 'UTF-8', value)
|
401
400
|
end
|
402
401
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
402
|
+
is_symbol ? encoded_value.to_sym : encoded_value
|
403
|
+
end
|
404
|
+
|
405
|
+
Rollbar::Util.iterate_and_update(payload, normalizer)
|
406
|
+
end
|
407
|
+
|
408
|
+
# Walks the entire payload and truncates string values that
|
409
|
+
# are longer than the byte_threshold
|
410
|
+
def truncate_payload(payload, byte_threshold)
|
411
|
+
truncator = proc do |value|
|
412
|
+
if value.is_a?(String) && value.bytesize > byte_threshold
|
413
|
+
Rollbar::Util.truncate(value, byte_threshold)
|
414
|
+
else
|
415
|
+
value
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
Rollbar::Util.iterate_and_update(payload, truncator)
|
420
|
+
end
|
421
|
+
|
422
|
+
## Delivery functions
|
423
|
+
|
424
|
+
def schedule_payload(payload)
|
425
|
+
log_info '[Rollbar] Scheduling payload'
|
426
|
+
|
427
|
+
if configuration.use_async
|
428
|
+
unless configuration.async_handler
|
429
|
+
configuration.async_handler = method(:default_async_handler)
|
430
|
+
end
|
431
|
+
|
432
|
+
if configuration.write_to_file
|
433
|
+
unless @file_semaphore
|
434
|
+
@file_semaphore = Mutex.new
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
configuration.async_handler.call(payload)
|
439
|
+
else
|
440
|
+
process_payload(payload)
|
408
441
|
end
|
409
442
|
end
|
410
443
|
|
@@ -421,6 +454,7 @@ module Rollbar
|
|
421
454
|
log_info "[Rollbar] Response: #{req.response}"
|
422
455
|
end
|
423
456
|
end
|
457
|
+
|
424
458
|
req.errback do
|
425
459
|
log_warning "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
|
426
460
|
log_info "[Rollbar] Error's response: #{req.response}"
|
@@ -437,6 +471,7 @@ module Rollbar
|
|
437
471
|
end
|
438
472
|
|
439
473
|
body = dump_payload(payload)
|
474
|
+
|
440
475
|
uri = URI.parse(configuration.endpoint)
|
441
476
|
http = Net::HTTP.new(uri.host, uri.port)
|
442
477
|
http.read_timeout = configuration.request_timeout
|
@@ -459,6 +494,72 @@ module Rollbar
|
|
459
494
|
end
|
460
495
|
end
|
461
496
|
|
497
|
+
def write_payload(payload)
|
498
|
+
if configuration.use_async
|
499
|
+
@file_semaphore.synchronize {
|
500
|
+
do_write_payload(payload)
|
501
|
+
}
|
502
|
+
else
|
503
|
+
do_write_payload(payload)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
def do_write_payload(payload)
|
508
|
+
log_info '[Rollbar] Writing payload to file'
|
509
|
+
|
510
|
+
begin
|
511
|
+
unless @file
|
512
|
+
@file = File.open(configuration.filepath, "a")
|
513
|
+
end
|
514
|
+
|
515
|
+
@file.puts payload
|
516
|
+
@file.flush
|
517
|
+
log_info "[Rollbar] Success"
|
518
|
+
rescue IOError => e
|
519
|
+
log_error "[Rollbar] Error opening/writing to file: #{e}"
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
def send_failsafe(message, exception)
|
524
|
+
log_error "[Rollbar] Sending failsafe response due to #{message}."
|
525
|
+
if exception
|
526
|
+
begin
|
527
|
+
log_error "[Rollbar] #{exception.class.name}: #{exception}"
|
528
|
+
rescue => e
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
config = configuration
|
533
|
+
environment = config.environment
|
534
|
+
|
535
|
+
failsafe_data = {
|
536
|
+
:level => 'error',
|
537
|
+
:environment => environment.to_s,
|
538
|
+
:body => {
|
539
|
+
:message => {
|
540
|
+
:body => "Failsafe from rollbar-gem: #{message}"
|
541
|
+
}
|
542
|
+
},
|
543
|
+
:notifier => {
|
544
|
+
:name => 'rollbar-gem',
|
545
|
+
:version => VERSION
|
546
|
+
},
|
547
|
+
:internal => true,
|
548
|
+
:failsafe => true
|
549
|
+
}
|
550
|
+
|
551
|
+
failsafe_payload = {
|
552
|
+
'access_token' => configuration.access_token,
|
553
|
+
'data' => failsafe_data
|
554
|
+
}
|
555
|
+
|
556
|
+
begin
|
557
|
+
schedule_payload(failsafe_payload)
|
558
|
+
rescue => e
|
559
|
+
log_error "[Rollbar] Error sending failsafe : #{e}"
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
462
563
|
def schedule_payload(payload)
|
463
564
|
return if payload.nil?
|
464
565
|
|
@@ -471,10 +572,16 @@ module Rollbar
|
|
471
572
|
end
|
472
573
|
end
|
473
574
|
|
575
|
+
def default_async_handler
|
576
|
+
return Rollbar::Delay::GirlFriday if defined?(GirlFriday)
|
577
|
+
|
578
|
+
Rollbar::Delay::Thread
|
579
|
+
end
|
580
|
+
|
474
581
|
def process_async_payload(payload)
|
475
582
|
configuration.async_handler ||= default_async_handler
|
476
583
|
configuration.async_handler.call(payload)
|
477
|
-
rescue
|
584
|
+
rescue => e
|
478
585
|
if configuration.failover_handlers.empty?
|
479
586
|
log_error '[Rollbar] Async handler failed, and there are no failover handlers configured. See the docs for "failover_handlers"'
|
480
587
|
return
|
@@ -499,16 +606,6 @@ module Rollbar
|
|
499
606
|
end
|
500
607
|
end
|
501
608
|
|
502
|
-
def build_payload(data)
|
503
|
-
payload = {
|
504
|
-
'access_token' => configuration.access_token,
|
505
|
-
'data' => data
|
506
|
-
}
|
507
|
-
|
508
|
-
enforce_valid_utf8(payload)
|
509
|
-
payload
|
510
|
-
end
|
511
|
-
|
512
609
|
def dump_payload(payload)
|
513
610
|
result = MultiJson.dump(payload)
|
514
611
|
|
@@ -537,154 +634,153 @@ module Rollbar
|
|
537
634
|
result
|
538
635
|
end
|
539
636
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
if environment.nil? || environment.empty?
|
545
|
-
environment = 'unspecified'
|
637
|
+
## Logging
|
638
|
+
%w(debug info warn error).each do |level|
|
639
|
+
define_method(:"log_#{level}") do |message|
|
640
|
+
logger.send(level, message)
|
546
641
|
end
|
642
|
+
end
|
547
643
|
|
548
|
-
|
549
|
-
:timestamp => Time.now.to_i,
|
550
|
-
:environment => environment,
|
551
|
-
:level => level,
|
552
|
-
:language => 'ruby',
|
553
|
-
:framework => config.framework,
|
554
|
-
:project_package_paths => config.project_gem_paths,
|
555
|
-
:notifier => {
|
556
|
-
:name => 'rollbar-gem',
|
557
|
-
:version => VERSION
|
558
|
-
}
|
559
|
-
}
|
644
|
+
alias_method :log_warning, :log_warn
|
560
645
|
|
561
|
-
|
562
|
-
|
646
|
+
def log_instance_link(data)
|
647
|
+
if data[:uuid]
|
648
|
+
log_info "[Rollbar] Details: #{configuration.web_base}/instance/uuid?uuid=#{data[:uuid]} (only available if report was successful)"
|
563
649
|
end
|
650
|
+
end
|
564
651
|
|
565
|
-
|
566
|
-
|
567
|
-
|
652
|
+
def logger
|
653
|
+
@logger ||= LoggerProxy.new(configuration.logger)
|
654
|
+
end
|
655
|
+
end
|
568
656
|
|
569
|
-
|
570
|
-
|
571
|
-
end
|
657
|
+
class << self
|
658
|
+
extend Forwardable
|
572
659
|
|
573
|
-
|
660
|
+
def_delegators :notifier, *PUBLIC_NOTIFIER_METHODS
|
661
|
+
|
662
|
+
# Similar to configure below, but used only internally within the gem
|
663
|
+
# to configure it without initializing any of the third party hooks
|
664
|
+
def preconfigure
|
665
|
+
yield(configuration)
|
574
666
|
end
|
575
667
|
|
576
|
-
def
|
577
|
-
|
668
|
+
def configure
|
669
|
+
# if configuration.enabled has not been set yet (is still 'nil'), set to true.
|
670
|
+
configuration.enabled = true if configuration.enabled.nil?
|
578
671
|
|
579
|
-
|
580
|
-
:host => Socket.gethostname
|
581
|
-
}
|
582
|
-
data[:root] = config.root.to_s if config.root
|
583
|
-
data[:branch] = config.branch if config.branch
|
672
|
+
yield(configuration)
|
584
673
|
|
585
|
-
|
674
|
+
require_hooks
|
586
675
|
end
|
587
676
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
677
|
+
def reconfigure
|
678
|
+
@configuration = Configuration.new
|
679
|
+
@configuration.enabled = true
|
680
|
+
yield(configuration)
|
681
|
+
end
|
593
682
|
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
send_failsafe("error in exception_data", e)
|
598
|
-
return
|
599
|
-
end
|
683
|
+
def unconfigure
|
684
|
+
@configuration = nil
|
685
|
+
end
|
600
686
|
|
601
|
-
|
687
|
+
def configuration
|
688
|
+
@configuration ||= Configuration.new
|
689
|
+
end
|
602
690
|
|
603
|
-
|
604
|
-
|
605
|
-
rescue => e
|
606
|
-
send_failsafe("error in build_payload", e)
|
607
|
-
return
|
608
|
-
end
|
691
|
+
def require_hooks
|
692
|
+
wrap_delayed_worker
|
609
693
|
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
694
|
+
require 'rollbar/sidekiq' if defined?(Sidekiq)
|
695
|
+
require 'rollbar/goalie' if defined?(Goalie)
|
696
|
+
require 'rollbar/rack' if defined?(Rack)
|
697
|
+
require 'rollbar/rake' if defined?(Rake)
|
698
|
+
require 'rollbar/better_errors' if defined?(BetterErrors)
|
699
|
+
end
|
616
700
|
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
end
|
701
|
+
def wrap_delayed_worker
|
702
|
+
return unless defined?(Delayed) && defined?(Delayed::Worker) && configuration.delayed_job_enabled
|
703
|
+
|
704
|
+
require 'rollbar/delayed_job'
|
705
|
+
Rollbar::Delayed.wrap_worker
|
623
706
|
end
|
624
707
|
|
625
|
-
def
|
626
|
-
|
627
|
-
|
628
|
-
begin
|
629
|
-
log_error "[Rollbar] #{exception.class.name}: #{exception}"
|
630
|
-
rescue => e
|
631
|
-
end
|
632
|
-
end
|
708
|
+
def notifier
|
709
|
+
Thread.current[:_rollbar_notifier] ||= Notifier.new(self)
|
710
|
+
end
|
633
711
|
|
634
|
-
|
635
|
-
|
712
|
+
def notifier=(notifier)
|
713
|
+
Thread.current[:_rollbar_notifier] = notifier
|
714
|
+
end
|
636
715
|
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
:body => { :message => { :body => "Failsafe from rollbar-gem: #{message}" } },
|
641
|
-
:notifier => { :name => 'rollbar-gem', :version => "#{VERSION}" },
|
642
|
-
:internal => true,
|
643
|
-
:failsafe => true
|
644
|
-
}
|
716
|
+
def last_report
|
717
|
+
Thread.current[:_rollbar_last_report]
|
718
|
+
end
|
645
719
|
|
646
|
-
|
720
|
+
def last_report=(report)
|
721
|
+
Thread.current[:_rollbar_last_report] = report
|
722
|
+
end
|
647
723
|
|
648
|
-
|
649
|
-
|
650
|
-
rescue => e
|
651
|
-
log_error "[Rollbar] Error sending failsafe : #{e}"
|
652
|
-
end
|
724
|
+
def reset_notifier!
|
725
|
+
self.notifier = nil
|
653
726
|
end
|
654
727
|
|
655
|
-
|
656
|
-
|
657
|
-
|
728
|
+
# Create a new Notifier instance using the received options and
|
729
|
+
# set it as the current thread notifier.
|
730
|
+
# The calls to Rollbar inside the received block will use then this
|
731
|
+
# new Notifier object.
|
732
|
+
#
|
733
|
+
# @example
|
734
|
+
#
|
735
|
+
# new_scope = { job_type: 'scheduled' }
|
736
|
+
# Rollbar.scoped(new_scope) do
|
737
|
+
# begin
|
738
|
+
# # do stuff
|
739
|
+
# rescue => e
|
740
|
+
# Rollbar.log(e)
|
741
|
+
# end
|
742
|
+
# end
|
743
|
+
def scoped(options = {})
|
744
|
+
old_notifier = notifier
|
745
|
+
self.notifier = old_notifier.scope(options)
|
658
746
|
|
659
|
-
|
747
|
+
result = yield
|
748
|
+
result
|
749
|
+
ensure
|
750
|
+
self.notifier = old_notifier
|
751
|
+
end
|
660
752
|
|
661
|
-
|
753
|
+
# Backwards compatibility methods
|
662
754
|
|
663
|
-
|
664
|
-
|
665
|
-
else
|
666
|
-
encoded_value = ::Iconv.conv('UTF-8//IGNORE', 'UTF-8', value)
|
667
|
-
end
|
755
|
+
def report_exception(exception, request_data = {}, person_data = {}, level = 'error')
|
756
|
+
Kernel.warn('[DEPRECATION] Rollbar.report_exception has been deprecated, please use log() or one of the level functions')
|
668
757
|
|
669
|
-
|
758
|
+
scope = {}
|
759
|
+
scope[:request] = request_data if request_data && request_data.any?
|
760
|
+
scope[:person] = person_data if person_data && person_data.any?
|
761
|
+
|
762
|
+
Rollbar.scoped(scope) do
|
763
|
+
Rollbar.notifier.log(level, exception)
|
670
764
|
end
|
765
|
+
end
|
671
766
|
|
672
|
-
|
767
|
+
def report_message(message, level = 'info', extra_data = {})
|
768
|
+
Kernel.warn('[DEPRECATION] Rollbar.report_message has been deprecated, please use log() or one of the level functions')
|
769
|
+
|
770
|
+
Rollbar.notifier.log(level, message, extra_data)
|
673
771
|
end
|
674
772
|
|
675
|
-
def
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
end
|
682
|
-
end
|
773
|
+
def report_message_with_request(message, level = 'info', request_data = {}, person_data = {}, extra_data = {})
|
774
|
+
Kernel.warn('[DEPRECATION] Rollbar.report_message_with_request has been deprecated, please use log() or one of the level functions')
|
775
|
+
|
776
|
+
scope = {}
|
777
|
+
scope[:request] = request_data if request_data && request_data.any?
|
778
|
+
scope[:person] = person_data if person_data && person_data.any?
|
683
779
|
|
684
|
-
|
780
|
+
|
781
|
+
Rollbar.scoped(:request => request_data, :person => person_data) do
|
782
|
+
Rollbar.notifier.log(level, message, extra_data)
|
783
|
+
end
|
685
784
|
end
|
686
785
|
end
|
687
786
|
end
|
688
|
-
|
689
|
-
# Setting Ratchetio as an alias to Rollbar for ratchetio-gem backwards compatibility
|
690
|
-
Ratchetio = Rollbar
|