rollbar 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/rollbar/rollbar-gem.png?branch=master)](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
|