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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ba9f625302b093e422f24c2c3a35a7e6388c099
4
- data.tar.gz: ef53f6cd97ed94d5db499b77c496a81f6c6eb6f8
3
+ metadata.gz: 850b8631306eb9e7c4e7379f869f573d74202b18
4
+ data.tar.gz: 10bbd67bc34a4635d5455b66c468bc3a4c65ce24
5
5
  SHA512:
6
- metadata.gz: 5752f3f6282c97ffce3142bd39089946eb79f0f7a9a864f9be56f74ec563ebc49b0839a92eb4388ef5d0445cc6f1fb80ae7ffc28860811e6884c5abf50257457
7
- data.tar.gz: c00267db9b445b402c2a84b3b608a3b3c23c17371611467ed79a173a1b6eb45a02f2e6d496c2b8131da45750cccb14723c55d61810ed6c65a82f1fa97d41231b
6
+ metadata.gz: 49809c4c002ff8a03d78b3c2b785bbf124ea754f4f54d668bf17bce21ab3bd9298fe9a15a09da2d50ba75b4ff7a6a03b03b601c1400aba6f2073c58128f49c4f
7
+ data.tar.gz: 204ec3d976719a22aa6333347d623ba17723d8574c2ab1c3b815f88631ebc996d3c4426619bbd8c8ddd88d34bab8a5a026cb9de0ed7f64d5c1202fca2d3d9408
@@ -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.1.0'
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
- Then, run the following command from your rails root:
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
- ### For Heroku users
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
- ## Reporting form validation errors
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
- ## Manually reporting exceptions and messages
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
- To report a caught exception to Rollbar, simply call ```Rollbar.report_exception```:
135
+ For example:
79
136
 
80
137
  ```ruby
81
- begin
82
- foo = bar
83
- rescue Exception => e
84
- Rollbar.report_exception(e)
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're reporting an exception in the context of a request and are in a controller, you can pass along the same request and person context as the global exception handler, like so:
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
- begin
92
- foo = bar
93
- rescue Exception => e
94
- Rollbar.report_exception(e, rollbar_request_data, rollbar_person_data)
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
- Exceptions are reported with an "error" level by default. You can override the level by passing it in as the fourth argument:
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
- begin
102
- foo = bar
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
- You can also log individual messages:
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.report_message("Unexpected input", "warning")
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
- # default level is "info"
116
- Rollbar.report_message("Login successful")
213
+ ## Special note about reporting within a request
117
214
 
118
- # can also include additional data as a hash in the final param. :body is reserved.
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
- # pass request and person data
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 requests before sending to Rollbar
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 lambda 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.
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 reported through ```Rollbar.report_exception()``` are reported at the "error" level, except for the following, which are reported at "warning" level:
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
 
@@ -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
+ ```
@@ -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 gem.
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 reconfigure
61
- @configuration = Configuration.new
62
- @configuration.enabled = true
63
- yield(configuration)
71
+ def scope(options = {})
72
+ self.class.new(self, options)
64
73
  end
65
74
 
66
- def unconfigure
67
- @configuration = nil
75
+ def configure
76
+ yield(configuration)
68
77
  end
69
78
 
70
- # Returns the configuration object.
79
+ # Turns off reporting for the given block.
71
80
  #
72
- # @return [Rollbar::Configuration] The configuration object
73
- def configuration
74
- @configuration ||= Configuration.new
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
- # Reports an exception to Rollbar. Returns the exception data hash.
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.report_exception(e)
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.report_message("User login failed", 'info', :user_id => 123)
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.report_message_with_request("User login failed", 'info', rollbar_request_data, rollbar_person_data, :foo => 'bar')
110
+ # Rollbar.log(e, 'This is a description of the exception')
147
111
  #
148
- # @param message [String] The message body. This will be used to identify the message within
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
- data = message_data(message, level, extra_data)
162
-
163
- attach_request_data(data, request_data) if request_data
164
- data[:person] = person_data if person_data
165
-
166
- @last_report = data
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
- payload = build_payload(data)
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
- yield
186
- rescue => e
187
- e.instance_variable_set(:@_rollbar_do_not_report, true)
188
- raise
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
- def process_payload(payload)
193
- begin
194
- if configuration.write_to_file
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
- # wrappers around logger methods
205
- def log_error(message)
206
- begin
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
- def log_info(message)
215
- begin
216
- logger.info message
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
- def log_warning(message)
224
- begin
225
- logger.warn message
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
- def log_debug(message)
233
- begin
234
- logger.debug message
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
- def default_async_handler
242
- return Rollbar::Delay::GirlFriday if defined?(GirlFriday)
243
-
244
- Rollbar::Delay::Thread
164
+ # See log() above
165
+ def critical(*args)
166
+ log('critical', *args)
245
167
  end
246
168
 
247
- private
248
-
249
- def attach_request_data(payload, request_data)
250
- if request_data[:route]
251
- route = request_data[:route]
252
-
253
- # make sure route is a hash built by RequestDataExtractor in rails apps
254
- if route.is_a?(Hash) and not route.empty?
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
- def log_instance_link(data)
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
- if filtered_level(exception) == 'ignore'
282
- return true
283
- end
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 message_data(message, level, extra_data)
302
- data = base_data(level)
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
- data[:body] = {
305
- :message => {
306
- :body => message.to_s
307
- }
308
- }
309
- data[:body][:message].merge!(extra_data)
310
- data[:server] = server_data
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
- def exception_data(exception, force_level = nil)
316
- data = base_data
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
- data[:level] = force_level if force_level
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
- traces = trace_chain(exception)
239
+ begin
240
+ process_payload(payload)
241
+ rescue => e
242
+ send_failsafe("error in process_payload", e)
243
+ return
244
+ end
321
245
 
322
- if traces.size > 1
323
- body = {
324
- :trace_chain => traces
325
- }
326
- elsif traces.size == 1
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
- data[:body] = body
254
+ ## Payload building functions
333
255
 
334
- data[:server] = server_data
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 trace_chain(exception)
340
- traces = [trace_data(exception)]
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
- while exception.respond_to?(:cause) && (cause = exception.cause)
343
- traces << trace_data(cause)
344
- exception = cause
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
- traces
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 logger
378
- # init if not set
379
- unless configuration.logger
380
- configuration.logger = configuration.default_logger.call
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
- configuration.logger
346
+
347
+ traces
383
348
  end
384
349
 
385
- def write_payload(payload)
386
- if configuration.use_async
387
- @file_semaphore.synchronize {
388
- do_write_payload(payload)
389
- }
390
- else
391
- do_write_payload(payload)
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 do_write_payload(payload)
396
- log_info '[Rollbar] Writing payload to file'
388
+ def enforce_valid_utf8(payload)
389
+ normalizer = lambda do |object|
390
+ is_symbol = object.is_a?(Symbol)
397
391
 
398
- begin
399
- unless @file
400
- @file = File.open(configuration.filepath, "a")
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
- @file.puts payload
404
- @file.flush
405
- log_info "[Rollbar] Success"
406
- rescue IOError => e
407
- log_error "[Rollbar] Error opening/writing to file: #{e}"
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
- def base_data(level = 'error')
541
- config = configuration
542
-
543
- environment = config.environment
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
- data = {
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
- if config.code_version
562
- data[:code_version] = config.code_version
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
- if defined?(SecureRandom) and SecureRandom.respond_to?(:uuid)
566
- data[:uuid] = SecureRandom.uuid
567
- end
652
+ def logger
653
+ @logger ||= LoggerProxy.new(configuration.logger)
654
+ end
655
+ end
568
656
 
569
- unless config.custom_data_method.nil?
570
- data[:custom] = config.custom_data_method.call
571
- end
657
+ class << self
658
+ extend Forwardable
572
659
 
573
- data
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 server_data
577
- config = configuration
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
- data = {
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
- data
674
+ require_hooks
586
675
  end
587
676
 
588
- # Reports an internal error in the Rollbar library. This will be reported within the configured
589
- # Rollbar project. We'll first attempt to provide a report including the exception traceback.
590
- # If that fails, we'll fall back to a more static failsafe response.
591
- def report_internal_error(exception)
592
- log_error "[Rollbar] Reporting internal error encountered while sending data to Rollbar."
677
+ def reconfigure
678
+ @configuration = Configuration.new
679
+ @configuration.enabled = true
680
+ yield(configuration)
681
+ end
593
682
 
594
- begin
595
- data = exception_data(exception, 'error')
596
- rescue => e
597
- send_failsafe("error in exception_data", e)
598
- return
599
- end
683
+ def unconfigure
684
+ @configuration = nil
685
+ end
600
686
 
601
- data[:internal] = true
687
+ def configuration
688
+ @configuration ||= Configuration.new
689
+ end
602
690
 
603
- begin
604
- payload = build_payload(data)
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
- begin
611
- schedule_payload(payload)
612
- rescue => e
613
- send_failsafe("error in schedule_payload", e)
614
- return
615
- end
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
- begin
618
- log_instance_link(data)
619
- rescue => e
620
- send_failsafe("error logging instance link", e)
621
- return
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 send_failsafe(message, exception)
626
- log_error "[Rollbar] Sending failsafe response due to #{message}."
627
- if exception
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
- config = configuration
635
- environment = config.environment
712
+ def notifier=(notifier)
713
+ Thread.current[:_rollbar_notifier] = notifier
714
+ end
636
715
 
637
- failsafe_data = {
638
- :level => 'error',
639
- :environment => "#{environment}",
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
- failsafe_payload = build_payload(failsafe_data)
720
+ def last_report=(report)
721
+ Thread.current[:_rollbar_last_report] = report
722
+ end
647
723
 
648
- begin
649
- schedule_payload(failsafe_payload)
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
- def enforce_valid_utf8(payload)
656
- normalizer = lambda do |object|
657
- is_symbol = object.is_a?(Symbol)
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
- return object unless object == object.to_s || is_symbol
747
+ result = yield
748
+ result
749
+ ensure
750
+ self.notifier = old_notifier
751
+ end
660
752
 
661
- value = object.to_s
753
+ # Backwards compatibility methods
662
754
 
663
- if value.respond_to? :encode
664
- encoded_value = value.encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
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
- is_symbol ? encoded_value.to_sym : encoded_value
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
- Rollbar::Util.iterate_and_update(payload, normalizer)
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 truncate_payload(payload, byte_threshold)
676
- truncator = Proc.new do |value|
677
- if value.is_a?(String) and value.bytesize > byte_threshold
678
- Rollbar::Util::truncate(value, byte_threshold)
679
- else
680
- value
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
- Rollbar::Util::iterate_and_update(payload, truncator)
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