rollbar 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +20 -0
- data/.travis.yml +17 -0
- data/CHANGELOG.md +90 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +165 -0
- data/Rakefile +14 -0
- data/THANKS +10 -0
- data/lib/generators/rollbar/rollbar_generator.rb +53 -0
- data/lib/generators/rollbar/templates/initializer.rb +28 -0
- data/lib/rollbar.rb +358 -0
- data/lib/rollbar/configuration.rb +64 -0
- data/lib/rollbar/delayed_job.rb +25 -0
- data/lib/rollbar/exception_reporter.rb +24 -0
- data/lib/rollbar/goalie.rb +33 -0
- data/lib/rollbar/middleware/rack/builder.rb +21 -0
- data/lib/rollbar/middleware/rack/test_session.rb +31 -0
- data/lib/rollbar/middleware/rails/show_exceptions.rb +26 -0
- data/lib/rollbar/rack.rb +9 -0
- data/lib/rollbar/rails.rb +22 -0
- data/lib/rollbar/rails/controller_methods.rb +28 -0
- data/lib/rollbar/railtie.rb +37 -0
- data/lib/rollbar/rake.rb +9 -0
- data/lib/rollbar/rake_tasks.rb +60 -0
- data/lib/rollbar/request_data_extractor.rb +115 -0
- data/lib/rollbar/sidekiq.rb +25 -0
- data/lib/rollbar/version.rb +3 -0
- data/rollbar.gemspec +24 -0
- data/spec/controllers/home_controller_spec.rb +180 -0
- data/spec/dummyapp/.gitignore +73 -0
- data/spec/dummyapp/Rakefile +7 -0
- data/spec/dummyapp/app/assets/javascripts/application.js +3 -0
- data/spec/dummyapp/app/assets/stylesheets/application.css.scss +37 -0
- data/spec/dummyapp/app/controllers/application_controller.rb +3 -0
- data/spec/dummyapp/app/controllers/home_controller.rb +25 -0
- data/spec/dummyapp/app/controllers/users_controller.rb +17 -0
- data/spec/dummyapp/app/helpers/.gitkeep +0 -0
- data/spec/dummyapp/app/mailers/.gitkeep +0 -0
- data/spec/dummyapp/app/models/.gitkeep +0 -0
- data/spec/dummyapp/app/models/user.rb +10 -0
- data/spec/dummyapp/app/views/devise/registrations/edit.html.erb +27 -0
- data/spec/dummyapp/app/views/devise/registrations/new.html.erb +20 -0
- data/spec/dummyapp/app/views/devise/shared/_links.html.erb +25 -0
- data/spec/dummyapp/app/views/home/cause_exception.html.erb +1 -0
- data/spec/dummyapp/app/views/home/index.html.erb +4 -0
- data/spec/dummyapp/app/views/home/report_exception.html.erb +1 -0
- data/spec/dummyapp/app/views/layouts/_messages.html.erb +5 -0
- data/spec/dummyapp/app/views/layouts/_navigation.html.erb +21 -0
- data/spec/dummyapp/app/views/layouts/application.html.erb +25 -0
- data/spec/dummyapp/app/views/users/index.html.erb +8 -0
- data/spec/dummyapp/app/views/users/show.html.erb +3 -0
- data/spec/dummyapp/config.ru +4 -0
- data/spec/dummyapp/config/application.rb +60 -0
- data/spec/dummyapp/config/boot.rb +10 -0
- data/spec/dummyapp/config/database.yml +25 -0
- data/spec/dummyapp/config/environment.rb +5 -0
- data/spec/dummyapp/config/environments/development.rb +37 -0
- data/spec/dummyapp/config/environments/production.rb +67 -0
- data/spec/dummyapp/config/environments/test.rb +37 -0
- data/spec/dummyapp/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummyapp/config/initializers/devise.rb +233 -0
- data/spec/dummyapp/config/initializers/inflections.rb +15 -0
- data/spec/dummyapp/config/initializers/mime_types.rb +5 -0
- data/spec/dummyapp/config/initializers/rollbar.rb +20 -0
- data/spec/dummyapp/config/initializers/secret_token.rb +7 -0
- data/spec/dummyapp/config/initializers/session_store.rb +8 -0
- data/spec/dummyapp/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummyapp/config/locales/devise.en.yml +58 -0
- data/spec/dummyapp/config/locales/en.yml +5 -0
- data/spec/dummyapp/config/routes.rb +14 -0
- data/spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb +46 -0
- data/spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb +5 -0
- data/spec/dummyapp/db/schema.rb +35 -0
- data/spec/dummyapp/db/seeds.rb +12 -0
- data/spec/dummyapp/lib/assets/.gitkeep +0 -0
- data/spec/dummyapp/public/404.html +26 -0
- data/spec/dummyapp/public/422.html +26 -0
- data/spec/dummyapp/public/500.html +25 -0
- data/spec/dummyapp/public/favicon.ico +0 -0
- data/spec/dummyapp/script/rails +6 -0
- data/spec/requests/home_spec.rb +48 -0
- data/spec/rollbar_spec.rb +426 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/support/devise.rb +3 -0
- metadata +282 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.8.7
|
4
|
+
- 1.9.3
|
5
|
+
- 1.9.2
|
6
|
+
- ruby-head
|
7
|
+
- jruby-18mode
|
8
|
+
- jruby-19mode
|
9
|
+
- jruby-head
|
10
|
+
- rbx-18mode
|
11
|
+
- rbx-19mode
|
12
|
+
matrix:
|
13
|
+
allow_failures:
|
14
|
+
- rvm: ruby-head
|
15
|
+
- rvm: rbx-18mode
|
16
|
+
- rvm: jruby-18mode
|
17
|
+
- rvm: jruby-19mode
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
**0.8.0**
|
4
|
+
- Rename to rollbar
|
5
|
+
|
6
|
+
**0.7.1**
|
7
|
+
- Fix ratchetio:test rake task when project base controller is not called ApplicationController
|
8
|
+
|
9
|
+
**0.7.0**
|
10
|
+
- Exceptions in Rake tasks are now automatically reported.
|
11
|
+
|
12
|
+
**0.6.4**
|
13
|
+
- Bump multi_json dependency version to 1.6.0
|
14
|
+
|
15
|
+
**0.6.3**
|
16
|
+
- Bump multi_json dependency version to 1.5.1
|
17
|
+
|
18
|
+
**0.6.2**
|
19
|
+
- Added EventMachine support
|
20
|
+
|
21
|
+
**0.6.1**
|
22
|
+
- Added a log message containing a link to the instance. Copy-paste the link into your browser to view its details in Ratchet.
|
23
|
+
- Ratchetio.report_message now returns 'ignored' or 'error' instead of nil when a message is not reported for one of those reasons, for consistency with Ratchetio.report_exception.
|
24
|
+
|
25
|
+
**0.6.0**
|
26
|
+
- POSSIBLE BREAKING CHANGE: Ratchetio.report_exception now returns 'ignored', 'disabled', or 'error' instead of nil when the exception is not reported for one of those reasons. It still returns the payload upon success.
|
27
|
+
- Request data is now parsed from the rack environment instead of from within the controller, addressing issue #10.
|
28
|
+
- Add Sidekiq middleware for catching workers' exceptions
|
29
|
+
- Replaced activesupport dependency with multi_json
|
30
|
+
|
31
|
+
**0.5.5**
|
32
|
+
- Added activesupport dependency for use without Rails
|
33
|
+
|
34
|
+
**0.5.4**
|
35
|
+
- Added new default scrub params
|
36
|
+
|
37
|
+
**0.5.3**
|
38
|
+
- Add `Ratchetio.silenced`; which allows disabling reporting for a given block. See README for usage.
|
39
|
+
|
40
|
+
**0.5.2**
|
41
|
+
- Fix compat issue with delayed_job below version 3. Exceptions raised by delayed_job below version 3 will not be automatically caught; upgrade to v3 or catch and report by hand.
|
42
|
+
|
43
|
+
**0.5.1**
|
44
|
+
- Save the exception uuid in `env['ratchetio.exception_uuid']` for display in user-facing error pages.
|
45
|
+
|
46
|
+
**0.5.0**
|
47
|
+
- Add support to report exceptions raised in delayed_job.
|
48
|
+
|
49
|
+
**0.4.11**
|
50
|
+
- Allow exceptions with no backtrace (e.g. StandardError subclasses)
|
51
|
+
|
52
|
+
**0.4.10**
|
53
|
+
- Fix compatability issue with ruby 1.8
|
54
|
+
|
55
|
+
**0.4.9**
|
56
|
+
- Start including a UUID in reported exceptions
|
57
|
+
- Fix issue with scrub_fields, and add `:password_confirmation` to the default list
|
58
|
+
|
59
|
+
**0.4.8**
|
60
|
+
- Add ability to send reports asynchronously, using girl_friday or Threading by default.
|
61
|
+
- Add ability to save reports to a file (for use with ratchet-agent) instead of sending across to Ratchet servers.
|
62
|
+
|
63
|
+
**0.4.7**
|
64
|
+
- Sensitive params now scrubbed out of requests. Param name list is customizable via the `scrub_fields` config option.
|
65
|
+
|
66
|
+
**0.4.6**
|
67
|
+
- Add support to play nicely with Goalie.
|
68
|
+
|
69
|
+
**0.4.5**
|
70
|
+
- Add `default_logger` config option. It should be a lambda that will return the logger to use if no other logger is configured (i.e. no logger is set by the Railtie hook). Default: `lambda { Logger.new(STDERR) }`
|
71
|
+
|
72
|
+
**0.4.4**
|
73
|
+
- Add `enabled` runtime config flag. When `false`, no data (messages or exceptions) will be reported.
|
74
|
+
|
75
|
+
**0.4.3**
|
76
|
+
- Add RSpec test suite. A few minor code changes.
|
77
|
+
|
78
|
+
**0.4.2**
|
79
|
+
- Add "ignore" filter level to completely ignore exceptions by class.
|
80
|
+
|
81
|
+
**0.4.1**
|
82
|
+
- Recursively filter files out of the params hash. Thanks to [trisweb](https://github.com/trisweb) for the pull request.
|
83
|
+
|
84
|
+
**0.4.0**
|
85
|
+
|
86
|
+
- Breaking change to make the "person" more configurable. If you were previously relying on your `current_member` method being called to return the person object, you will need to add the following line to `config/initializers/ratchetio.rb`:
|
87
|
+
|
88
|
+
config.person_method = "current_member"
|
89
|
+
|
90
|
+
- Person id, username, and email method names are now configurable -- see README for details.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rollbar, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# Rollbar [](https://travis-ci.org/rollbar/rollbar-gem)
|
2
|
+
|
3
|
+
Ruby gem for Rollbar, for reporting exceptions in Rails 3 to Rollbar. Requires a Rollbar account (you can sign up for free).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rollbar'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rollbar
|
18
|
+
|
19
|
+
Then, run the following command from your rails root:
|
20
|
+
|
21
|
+
$ rails generate rollbar YOUR_ROLLBAR_PROJECT_ACCESS_TOKEN
|
22
|
+
|
23
|
+
That will create the file `config/initializers/rollbar.rb`, which holds the configuration values (currently just your access token) and is all you need to use Rollbar with Rails.
|
24
|
+
|
25
|
+
To confirm that it worked, run:
|
26
|
+
|
27
|
+
$ rake rollbar:test
|
28
|
+
|
29
|
+
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.
|
30
|
+
|
31
|
+
## Manually reporting exceptions and messages
|
32
|
+
|
33
|
+
To report a caught exception to Rollbar, simply call `Rollbar.report_exception`:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
begin
|
37
|
+
foo = bar
|
38
|
+
rescue Exception => e
|
39
|
+
Rollbar.report_exception(e)
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
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:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
begin
|
47
|
+
foo = bar
|
48
|
+
rescue Exception => e
|
49
|
+
Rollbar.report_exception(e, rollbar_request_data, rollbar_person_data)
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
You can also log individual messages:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# logs at the 'warning' level. all levels: debug, info, warning, error, critical
|
57
|
+
Rollbar.report_message("Unexpected input", "warning")
|
58
|
+
|
59
|
+
# default level is "info"
|
60
|
+
Rollbar.report_message("Login successful")
|
61
|
+
|
62
|
+
# can also include additional data as a hash in the final param. :body is reserved.
|
63
|
+
Rollbar.report_message("Login successful", "info", :user => @user)
|
64
|
+
```
|
65
|
+
|
66
|
+
|
67
|
+
## Person tracking
|
68
|
+
|
69
|
+
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.
|
70
|
+
|
71
|
+
If the gem should call a controller method besides `current_user`, add the following in `config/initializers/rollbar.rb`:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
config.person_method = "my_current_user"
|
75
|
+
```
|
76
|
+
|
77
|
+
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`:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
config.person_id_method = "user_id" # default is "id"
|
81
|
+
config.person_username_method = "user_name" # default is "username"
|
82
|
+
config.person_email_method = "email_address" # default is "email"
|
83
|
+
```
|
84
|
+
|
85
|
+
|
86
|
+
## Exception level filters
|
87
|
+
|
88
|
+
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:
|
89
|
+
|
90
|
+
- ActiveRecord::RecordNotFound
|
91
|
+
- AbstractController::ActionNotFound
|
92
|
+
- ActionController::RoutingError
|
93
|
+
|
94
|
+
If you'd like to customize this list, see the example code in `config/initializers/rollbar.rb`. Supported levels: "critical", "error", "warning", "info", "debug", "ignore". Set to "ignore" to cause the exception not to be reported at all.
|
95
|
+
|
96
|
+
|
97
|
+
## Silencing exceptions at runtime
|
98
|
+
|
99
|
+
If you just want to disable exception reporting for a single block, use `Rollbar.silenced`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Rollbar.silenced {
|
103
|
+
foo = bar # will not be reported
|
104
|
+
}
|
105
|
+
```
|
106
|
+
|
107
|
+
|
108
|
+
## Asynchronous reporting
|
109
|
+
|
110
|
+
By default, all messages are reported synchronously. You can enable asynchronous reporting by adding the following in `config/initializers/rollbar.rb`:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
config.use_async = true
|
114
|
+
```
|
115
|
+
|
116
|
+
Rollbar uses [girl_friday](https://github.com/mperham/girl_friday) to handle asynchronous reporting when installed, and falls back to Threading if girl_friday is not installed.
|
117
|
+
|
118
|
+
You can supply your own handler using `config.async_handler`. The handler should schedule the payload for later processing (i.e. with a delayed_job, in a resque queue, etc.) and should itself return immediately. For example:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
config.async_handler = Proc.new { |payload|
|
122
|
+
Thread.new { Rollbar.process_payload(payload) }
|
123
|
+
}
|
124
|
+
```
|
125
|
+
|
126
|
+
Make sure you pass `payload` to `Rollbar.process_payload` in your own implementation.
|
127
|
+
|
128
|
+
|
129
|
+
## Using with rollbar-agent
|
130
|
+
|
131
|
+
For even more asynchrony, you can configure the gem to write to a file instead of sending the payload to Rollbar servers directly. [rollbar-agent](https://github.com/rollbar/rollbar-agent) can then be hooked up to this file to actually send the payload across. To enable, add the following in `config/initializers/rollbar.rb`:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
config.write_to_file = true
|
135
|
+
# optional, defaults to "#{AppName}.rollbar"
|
136
|
+
config.filepath = '/path/to/file.rollbar' #should end in '.rollbar' for use with rollbar-agent
|
137
|
+
```
|
138
|
+
|
139
|
+
For this to work, you'll also need to set up rollbar-agent--see its docs for details.
|
140
|
+
|
141
|
+
|
142
|
+
## Using with Goalie
|
143
|
+
|
144
|
+
If you're using [Goalie](https://github.com/obvio171/goalie) for custom error pages, you may need to explicitly add `require 'goalie'` to `config/application.rb` (in addition to `require 'goalie/rails'`) so that the monkeypatch will work. (This will be obvious if it is needed because your app won't start up: you'll see a cryptic error message about `Goalie::CustomErrorPages.render_exception` not being defined.)
|
145
|
+
|
146
|
+
|
147
|
+
## Using with Resque
|
148
|
+
|
149
|
+
Check out [resque-ratchetio](https://github.com/CrowdFlower/resque-ratchetio) for using Rollbar as a failure backend for Resque.
|
150
|
+
|
151
|
+
|
152
|
+
## Help / Support
|
153
|
+
|
154
|
+
If you run into any issues, please email us at `support@rollbar.com`
|
155
|
+
|
156
|
+
|
157
|
+
## Contributing
|
158
|
+
|
159
|
+
1. Fork it
|
160
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
161
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
162
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
163
|
+
5. Create new Pull Request
|
164
|
+
|
165
|
+
We're using RSpec for testing. Run the test suite with `rake spec`. Tests for pull requests are appreciated but not required. (If you don't include a test, we'll write one before merging.)
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
namespace :dummy do
|
8
|
+
load 'spec/dummyapp/Rakefile'
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Run specs'
|
12
|
+
task :default => ['dummy:db:setup'] do
|
13
|
+
Rake::Task[:spec].invoke
|
14
|
+
end
|
data/THANKS
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/named_base'
|
3
|
+
|
4
|
+
module Rollbar
|
5
|
+
module Generators
|
6
|
+
class RollbarGenerator < ::Rails::Generators::Base
|
7
|
+
argument :access_token, :type => :string, :banner => 'access_token'
|
8
|
+
|
9
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
10
|
+
|
11
|
+
def create_initializer
|
12
|
+
puts "creating initializer..."
|
13
|
+
if access_token_configured?
|
14
|
+
puts "It looks like you've already configured Rollbar."
|
15
|
+
puts "To re-create the config file, remove it first: config/initializers/rollbar.rb"
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
puts "access token: " << access_token
|
20
|
+
|
21
|
+
template 'initializer.rb', 'config/initializers/rollbar.rb',
|
22
|
+
:assigns => { :access_token => access_token_expr }
|
23
|
+
|
24
|
+
# TODO run rake test task
|
25
|
+
end
|
26
|
+
|
27
|
+
#def add_options!(opt)
|
28
|
+
# opt.on('-a', '--access-token=token', String, "Your Rollbar project access token") { |v| options[:access_token] = v }
|
29
|
+
#end
|
30
|
+
#
|
31
|
+
# def manifest
|
32
|
+
# if !access_token_configured? && !options[:access_token]
|
33
|
+
# puts "access_token is required. Pass --access-token=YOUR_ACCESS_TOKEN"
|
34
|
+
# exit
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# record do |m|
|
38
|
+
# m.template 'initializer.rb', 'config/initializers/rollbar.rb',
|
39
|
+
# :assigns => { :access_token => access_token_expr }
|
40
|
+
# # TODO run rake test task
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
|
44
|
+
def access_token_expr
|
45
|
+
"'#{access_token}'"
|
46
|
+
end
|
47
|
+
|
48
|
+
def access_token_configured?
|
49
|
+
File.exists?('config/initializers/rollbar.rb')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rollbar/rails'
|
2
|
+
Rollbar.configure do |config|
|
3
|
+
config.access_token = <%= access_token_expr %>
|
4
|
+
|
5
|
+
# By default, Rollbar will try to call the `current_user` controller method
|
6
|
+
# to fetch the logged-in user object, and then call that object's `id`,
|
7
|
+
# `username`, and `email` methods to fetch those properties. To customize:
|
8
|
+
# config.person_method = "my_current_user"
|
9
|
+
# config.person_id_method = "my_id"
|
10
|
+
# config.person_username_method = "my_username"
|
11
|
+
# config.person_email_method = "my_email"
|
12
|
+
|
13
|
+
# Add exception class names to the exception_level_filters hash to
|
14
|
+
# change the level that exception is reported at. Note that if an exception
|
15
|
+
# has already been reported and logged the level will need to be changed
|
16
|
+
# via the rollbar interface.
|
17
|
+
# Valid levels: 'critical', 'error', 'warning', 'info', 'debug', 'ignore'
|
18
|
+
# 'ignore' will cause the exception to not be reported at all.
|
19
|
+
# config.exception_level_filters.merge!('MyCriticalException' => 'critical')
|
20
|
+
|
21
|
+
# Enable asynchronous reporting (uses girl_friday or Threading if girl_friday
|
22
|
+
# is not installed)
|
23
|
+
# config.use_async = true
|
24
|
+
# Supply your own async handler:
|
25
|
+
# config.async_handler = Proc.new { |payload|
|
26
|
+
# Thread.new { Rollbar.process_payload(payload) }
|
27
|
+
# }
|
28
|
+
end
|
data/lib/rollbar.rb
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'securerandom' if defined?(SecureRandom)
|
3
|
+
require 'socket'
|
4
|
+
require 'thread'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require "girl_friday" if defined?(GirlFriday)
|
8
|
+
|
9
|
+
require 'rollbar/version'
|
10
|
+
require 'rollbar/configuration'
|
11
|
+
require 'rollbar/request_data_extractor'
|
12
|
+
require 'rollbar/exception_reporter'
|
13
|
+
|
14
|
+
require 'rollbar/delayed_job' if defined?(Delayed) && defined?(Delayed::Plugins)
|
15
|
+
require 'rollbar/sidekiq' if defined?(Sidekiq)
|
16
|
+
require 'rollbar/goalie' if defined?(Goalie)
|
17
|
+
require 'rollbar/rack' if defined?(Rack)
|
18
|
+
require 'rollbar/rake' if defined?(Rake)
|
19
|
+
require 'rollbar/railtie' if defined?(Rails)
|
20
|
+
|
21
|
+
module Rollbar
|
22
|
+
class << self
|
23
|
+
attr_writer :configuration
|
24
|
+
attr_reader :last_report
|
25
|
+
|
26
|
+
# Configures the gem.
|
27
|
+
#
|
28
|
+
# Call on app startup to set the `access_token` (required) and other config params.
|
29
|
+
# In a Rails app, this is called by `config/initializers/rollbar.rb` which is generated
|
30
|
+
# with `rails generate rollbar access-token-here`
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# Rollbar.configure do |config|
|
34
|
+
# config.access_token = 'abcdefg'
|
35
|
+
# end
|
36
|
+
def configure
|
37
|
+
yield(configuration)
|
38
|
+
end
|
39
|
+
|
40
|
+
def reconfigure
|
41
|
+
@configuration = Configuration.new
|
42
|
+
yield(configuration)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the configuration object.
|
46
|
+
#
|
47
|
+
# @return [Rollbar::Configuration] The configuration object
|
48
|
+
def configuration
|
49
|
+
@configuration ||= Configuration.new
|
50
|
+
end
|
51
|
+
|
52
|
+
# Reports an exception to Rollbar. Returns the exception data hash.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# begin
|
56
|
+
# foo = bar
|
57
|
+
# rescue => e
|
58
|
+
# Rollbar.report_exception(e)
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# @param exception [Exception] The exception object to report
|
62
|
+
# @param request_data [Hash] Data describing the request. Should be the result of calling
|
63
|
+
# `rollbar_request_data`.
|
64
|
+
# @param person_data [Hash] Data describing the affected person. Should be the result of calling
|
65
|
+
# `rollbar_person_data`
|
66
|
+
def report_exception(exception, request_data = nil, person_data = nil)
|
67
|
+
return 'disabled' unless configuration.enabled
|
68
|
+
return 'ignored' if ignored?(exception)
|
69
|
+
|
70
|
+
data = exception_data(exception, filtered_level(exception))
|
71
|
+
data[:request] = request_data if request_data
|
72
|
+
data[:person] = person_data if person_data
|
73
|
+
|
74
|
+
@last_report = data
|
75
|
+
|
76
|
+
payload = build_payload(data)
|
77
|
+
schedule_payload(payload)
|
78
|
+
log_instance_link(data)
|
79
|
+
data
|
80
|
+
rescue => e
|
81
|
+
logger.error "[Rollbar] Error reporting exception to Rollbar: #{e}"
|
82
|
+
'error'
|
83
|
+
end
|
84
|
+
|
85
|
+
# Reports an arbitrary message to Rollbar
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# Rollbar.report_message("User login failed", 'info', :user_id => 123)
|
89
|
+
#
|
90
|
+
# @param message [String] The message body. This will be used to identify the message within
|
91
|
+
# Rollbar. For best results, avoid putting variables in the message body; pass them as
|
92
|
+
# `extra_data` instead.
|
93
|
+
# @param level [String] The level. One of: 'critical', 'error', 'warning', 'info', 'debug'
|
94
|
+
# @param extra_data [Hash] Additional data to include alongside the body. Don't use 'body' as
|
95
|
+
# it is reserved.
|
96
|
+
def report_message(message, level = 'info', extra_data = {})
|
97
|
+
return 'disabled' unless configuration.enabled
|
98
|
+
|
99
|
+
data = message_data(message, level, extra_data)
|
100
|
+
payload = build_payload(data)
|
101
|
+
schedule_payload(payload)
|
102
|
+
log_instance_link(data)
|
103
|
+
data
|
104
|
+
rescue => e
|
105
|
+
logger.error "[Rollbar] Error reporting message to Rollbar: #{e}"
|
106
|
+
'error'
|
107
|
+
end
|
108
|
+
|
109
|
+
# Turns off reporting for the given block.
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# Rollbar.silenced { raise }
|
113
|
+
#
|
114
|
+
# @yield Block which exceptions won't be reported.
|
115
|
+
def silenced
|
116
|
+
begin
|
117
|
+
yield
|
118
|
+
rescue => e
|
119
|
+
e.instance_variable_set(:@_rollbar_do_not_report, true)
|
120
|
+
raise
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def process_payload(payload)
|
125
|
+
begin
|
126
|
+
if configuration.write_to_file
|
127
|
+
write_payload(payload)
|
128
|
+
else
|
129
|
+
send_payload(payload)
|
130
|
+
end
|
131
|
+
rescue => e
|
132
|
+
logger.error "[Rollbar] Error reporting message to Rollbar: #{e}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def log_instance_link(data)
|
139
|
+
logger.info "[Rollbar] Details: #{configuration.web_base}/instance/uuid?uuid=#{data[:uuid]}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def ignored?(exception)
|
143
|
+
if filtered_level(exception) == 'ignore'
|
144
|
+
return true
|
145
|
+
end
|
146
|
+
|
147
|
+
if exception.instance_variable_get(:@_rollbar_do_not_report)
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
|
151
|
+
false
|
152
|
+
end
|
153
|
+
|
154
|
+
def filtered_level(exception)
|
155
|
+
configuration.exception_level_filters[exception.class.name]
|
156
|
+
end
|
157
|
+
|
158
|
+
def message_data(message, level, extra_data)
|
159
|
+
data = base_data(level)
|
160
|
+
|
161
|
+
data[:body] = {
|
162
|
+
:message => {
|
163
|
+
:body => message.to_s
|
164
|
+
}
|
165
|
+
}
|
166
|
+
data[:body][:message].merge!(extra_data)
|
167
|
+
data[:server] = server_data
|
168
|
+
|
169
|
+
data
|
170
|
+
end
|
171
|
+
|
172
|
+
def exception_data(exception, force_level = nil)
|
173
|
+
data = base_data
|
174
|
+
|
175
|
+
data[:level] = force_level if force_level
|
176
|
+
|
177
|
+
# parse backtrace
|
178
|
+
if exception.backtrace.respond_to?( :map )
|
179
|
+
frames = exception.backtrace.map { |frame|
|
180
|
+
# parse the line
|
181
|
+
match = frame.match(/(.*):(\d+)(?::in `([^']+)')?/)
|
182
|
+
{ :filename => match[1], :lineno => match[2].to_i, :method => match[3] }
|
183
|
+
}
|
184
|
+
# reverse so that the order is as rollbar expects
|
185
|
+
frames.reverse!
|
186
|
+
else
|
187
|
+
frames = []
|
188
|
+
end
|
189
|
+
|
190
|
+
data[:body] = {
|
191
|
+
:trace => {
|
192
|
+
:frames => frames,
|
193
|
+
:exception => {
|
194
|
+
:class => exception.class.name,
|
195
|
+
:message => exception.message
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
data[:server] = server_data
|
201
|
+
|
202
|
+
data
|
203
|
+
end
|
204
|
+
|
205
|
+
def logger
|
206
|
+
# init if not set
|
207
|
+
unless configuration.logger
|
208
|
+
configuration.logger = configuration.default_logger.call
|
209
|
+
end
|
210
|
+
configuration.logger
|
211
|
+
end
|
212
|
+
|
213
|
+
def write_payload(payload)
|
214
|
+
if configuration.use_async
|
215
|
+
@file_semaphore.synchronize {
|
216
|
+
do_write_payload(payload)
|
217
|
+
}
|
218
|
+
else
|
219
|
+
do_write_payload(payload)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def do_write_payload(payload)
|
224
|
+
logger.info '[Rollbar] Writing payload to file'
|
225
|
+
|
226
|
+
begin
|
227
|
+
unless @file
|
228
|
+
@file = File.open(configuration.filepath, "a")
|
229
|
+
end
|
230
|
+
|
231
|
+
@file.puts payload
|
232
|
+
@file.flush
|
233
|
+
logger.info "[Rollbar] Success"
|
234
|
+
rescue IOError => e
|
235
|
+
logger.error "[Rollbar] Error opening/writing to file: #{e}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def send_payload_using_eventmachine(payload)
|
240
|
+
req = EventMachine::HttpRequest.new(configuration.endpoint).post(:body => payload)
|
241
|
+
req.callback do
|
242
|
+
if req.response_header.status == 200
|
243
|
+
logger.info '[Rollbar] Success'
|
244
|
+
else
|
245
|
+
logger.warn "[Rollbar] Got unexpected status code from Rollbar.io api: #{req.response_header.status}"
|
246
|
+
logger.info "[Rollbar] Response: #{req.response}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
req.errback do
|
250
|
+
logger.warn "[Rollbar] Call to API failed, status code: #{req.response_header.status}"
|
251
|
+
logger.info "[Rollbar] Error's response: #{req.response}"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def send_payload(payload)
|
256
|
+
logger.info '[Rollbar] Sending payload'
|
257
|
+
|
258
|
+
if configuration.use_eventmachine
|
259
|
+
send_payload_using_eventmachine(payload)
|
260
|
+
return
|
261
|
+
end
|
262
|
+
uri = URI.parse(configuration.endpoint)
|
263
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
264
|
+
|
265
|
+
if uri.scheme == 'https'
|
266
|
+
http.use_ssl = true
|
267
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
268
|
+
end
|
269
|
+
|
270
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
271
|
+
request.body = payload
|
272
|
+
response = http.request(request)
|
273
|
+
|
274
|
+
if response.code == '200'
|
275
|
+
logger.info '[Rollbar] Success'
|
276
|
+
else
|
277
|
+
logger.warn "[Rollbar] Got unexpected status code from Rollbar api: #{response.code}"
|
278
|
+
logger.info "[Rollbar] Response: #{response.body}"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def schedule_payload(payload)
|
283
|
+
logger.info '[Rollbar] Scheduling payload'
|
284
|
+
|
285
|
+
if configuration.use_async
|
286
|
+
unless configuration.async_handler
|
287
|
+
configuration.async_handler = method(:default_async_handler)
|
288
|
+
end
|
289
|
+
|
290
|
+
if configuration.write_to_file
|
291
|
+
unless @file_semaphore
|
292
|
+
@file_semaphore = Mutex.new
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
configuration.async_handler.call(payload)
|
297
|
+
else
|
298
|
+
process_payload(payload)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def build_payload(data)
|
303
|
+
payload = {
|
304
|
+
:access_token => configuration.access_token,
|
305
|
+
:data => data
|
306
|
+
}
|
307
|
+
MultiJson.dump(payload)
|
308
|
+
end
|
309
|
+
|
310
|
+
def base_data(level = 'error')
|
311
|
+
config = configuration
|
312
|
+
data = {
|
313
|
+
:timestamp => Time.now.to_i,
|
314
|
+
:environment => config.environment,
|
315
|
+
:level => level,
|
316
|
+
:language => 'ruby',
|
317
|
+
:framework => config.framework,
|
318
|
+
:notifier => {
|
319
|
+
:name => 'rollbar-gem',
|
320
|
+
:version => VERSION
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
if defined?(SecureRandom) and SecureRandom.respond_to?(:uuid)
|
325
|
+
data[:uuid] = SecureRandom.uuid
|
326
|
+
end
|
327
|
+
|
328
|
+
data
|
329
|
+
end
|
330
|
+
|
331
|
+
def server_data
|
332
|
+
config = configuration
|
333
|
+
|
334
|
+
data = {
|
335
|
+
:host => Socket.gethostname
|
336
|
+
}
|
337
|
+
data[:root] = config.root.to_s if config.root
|
338
|
+
data[:branch] = config.branch if config.branch
|
339
|
+
|
340
|
+
data
|
341
|
+
end
|
342
|
+
|
343
|
+
def default_async_handler(payload)
|
344
|
+
if defined?(GirlFriday)
|
345
|
+
unless @queue
|
346
|
+
@queue = GirlFriday::WorkQueue.new(nil, :size => 5) do |payload|
|
347
|
+
process_payload(payload)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
@queue.push(payload)
|
352
|
+
else
|
353
|
+
logger.warn '[Rollbar] girl_friday not found to handle async call, falling back to Thread'
|
354
|
+
Thread.new { process_payload(payload) }
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|