rollbar 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/.gitignore +20 -0
  2. data/.travis.yml +17 -0
  3. data/CHANGELOG.md +90 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +22 -0
  6. data/README.md +165 -0
  7. data/Rakefile +14 -0
  8. data/THANKS +10 -0
  9. data/lib/generators/rollbar/rollbar_generator.rb +53 -0
  10. data/lib/generators/rollbar/templates/initializer.rb +28 -0
  11. data/lib/rollbar.rb +358 -0
  12. data/lib/rollbar/configuration.rb +64 -0
  13. data/lib/rollbar/delayed_job.rb +25 -0
  14. data/lib/rollbar/exception_reporter.rb +24 -0
  15. data/lib/rollbar/goalie.rb +33 -0
  16. data/lib/rollbar/middleware/rack/builder.rb +21 -0
  17. data/lib/rollbar/middleware/rack/test_session.rb +31 -0
  18. data/lib/rollbar/middleware/rails/show_exceptions.rb +26 -0
  19. data/lib/rollbar/rack.rb +9 -0
  20. data/lib/rollbar/rails.rb +22 -0
  21. data/lib/rollbar/rails/controller_methods.rb +28 -0
  22. data/lib/rollbar/railtie.rb +37 -0
  23. data/lib/rollbar/rake.rb +9 -0
  24. data/lib/rollbar/rake_tasks.rb +60 -0
  25. data/lib/rollbar/request_data_extractor.rb +115 -0
  26. data/lib/rollbar/sidekiq.rb +25 -0
  27. data/lib/rollbar/version.rb +3 -0
  28. data/rollbar.gemspec +24 -0
  29. data/spec/controllers/home_controller_spec.rb +180 -0
  30. data/spec/dummyapp/.gitignore +73 -0
  31. data/spec/dummyapp/Rakefile +7 -0
  32. data/spec/dummyapp/app/assets/javascripts/application.js +3 -0
  33. data/spec/dummyapp/app/assets/stylesheets/application.css.scss +37 -0
  34. data/spec/dummyapp/app/controllers/application_controller.rb +3 -0
  35. data/spec/dummyapp/app/controllers/home_controller.rb +25 -0
  36. data/spec/dummyapp/app/controllers/users_controller.rb +17 -0
  37. data/spec/dummyapp/app/helpers/.gitkeep +0 -0
  38. data/spec/dummyapp/app/mailers/.gitkeep +0 -0
  39. data/spec/dummyapp/app/models/.gitkeep +0 -0
  40. data/spec/dummyapp/app/models/user.rb +10 -0
  41. data/spec/dummyapp/app/views/devise/registrations/edit.html.erb +27 -0
  42. data/spec/dummyapp/app/views/devise/registrations/new.html.erb +20 -0
  43. data/spec/dummyapp/app/views/devise/shared/_links.html.erb +25 -0
  44. data/spec/dummyapp/app/views/home/cause_exception.html.erb +1 -0
  45. data/spec/dummyapp/app/views/home/index.html.erb +4 -0
  46. data/spec/dummyapp/app/views/home/report_exception.html.erb +1 -0
  47. data/spec/dummyapp/app/views/layouts/_messages.html.erb +5 -0
  48. data/spec/dummyapp/app/views/layouts/_navigation.html.erb +21 -0
  49. data/spec/dummyapp/app/views/layouts/application.html.erb +25 -0
  50. data/spec/dummyapp/app/views/users/index.html.erb +8 -0
  51. data/spec/dummyapp/app/views/users/show.html.erb +3 -0
  52. data/spec/dummyapp/config.ru +4 -0
  53. data/spec/dummyapp/config/application.rb +60 -0
  54. data/spec/dummyapp/config/boot.rb +10 -0
  55. data/spec/dummyapp/config/database.yml +25 -0
  56. data/spec/dummyapp/config/environment.rb +5 -0
  57. data/spec/dummyapp/config/environments/development.rb +37 -0
  58. data/spec/dummyapp/config/environments/production.rb +67 -0
  59. data/spec/dummyapp/config/environments/test.rb +37 -0
  60. data/spec/dummyapp/config/initializers/backtrace_silencers.rb +7 -0
  61. data/spec/dummyapp/config/initializers/devise.rb +233 -0
  62. data/spec/dummyapp/config/initializers/inflections.rb +15 -0
  63. data/spec/dummyapp/config/initializers/mime_types.rb +5 -0
  64. data/spec/dummyapp/config/initializers/rollbar.rb +20 -0
  65. data/spec/dummyapp/config/initializers/secret_token.rb +7 -0
  66. data/spec/dummyapp/config/initializers/session_store.rb +8 -0
  67. data/spec/dummyapp/config/initializers/wrap_parameters.rb +14 -0
  68. data/spec/dummyapp/config/locales/devise.en.yml +58 -0
  69. data/spec/dummyapp/config/locales/en.yml +5 -0
  70. data/spec/dummyapp/config/routes.rb +14 -0
  71. data/spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb +46 -0
  72. data/spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb +5 -0
  73. data/spec/dummyapp/db/schema.rb +35 -0
  74. data/spec/dummyapp/db/seeds.rb +12 -0
  75. data/spec/dummyapp/lib/assets/.gitkeep +0 -0
  76. data/spec/dummyapp/public/404.html +26 -0
  77. data/spec/dummyapp/public/422.html +26 -0
  78. data/spec/dummyapp/public/500.html +25 -0
  79. data/spec/dummyapp/public/favicon.ico +0 -0
  80. data/spec/dummyapp/script/rails +6 -0
  81. data/spec/requests/home_spec.rb +48 -0
  82. data/spec/rollbar_spec.rb +426 -0
  83. data/spec/spec_helper.rb +35 -0
  84. data/spec/support/devise.rb +3 -0
  85. metadata +282 -0
@@ -0,0 +1,15 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new inflection rules using the following format
4
+ # (all these examples are active by default):
5
+ # ActiveSupport::Inflector.inflections do |inflect|
6
+ # inflect.plural /^(ox)$/i, '\1en'
7
+ # inflect.singular /^(ox)en/i, '\1'
8
+ # inflect.irregular 'person', 'people'
9
+ # inflect.uncountable %w( fish sheep )
10
+ # end
11
+ #
12
+ # These inflection rules are supported but not enabled by default:
13
+ # ActiveSupport::Inflector.inflections do |inflect|
14
+ # inflect.acronym 'RESTful'
15
+ # end
@@ -0,0 +1,5 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
5
+ # Mime::Type.register_alias "text/html", :iphone
@@ -0,0 +1,20 @@
1
+ require 'rollbar/rails'
2
+ Rollbar.configure do |config|
3
+ config.access_token = 'aaaabbbbccccddddeeeeffff00001111'
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
+ end
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ Dummy::Application.config.secret_token = '61f244779bab3ceba188492a31fb02b0a975fb64b93e217c03966ef065f5f1aba3b145c165defe0f8256e45cc6c526a60c9780a506a16e730815a3f812b5f9e9'
@@ -0,0 +1,8 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Dummy::Application.config.session_store :cookie_store, :key => '_dummy_session'
4
+
5
+ # Use the database for sessions instead of the cookie-based default,
6
+ # which shouldn't be used to store highly confidential information
7
+ # (create the session table with "rails generate session_migration")
8
+ # Dummy::Application.config.session_store :active_record_store
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+ #
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters :format => [:json]
9
+ end
10
+
11
+ # Disable root element in JSON by default.
12
+ ActiveSupport.on_load(:active_record) do
13
+ self.include_root_in_json = false
14
+ end
@@ -0,0 +1,58 @@
1
+ # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2
+
3
+ en:
4
+ errors:
5
+ messages:
6
+ expired: "has expired, please request a new one"
7
+ not_found: "not found"
8
+ already_confirmed: "was already confirmed, please try signing in"
9
+ not_locked: "was not locked"
10
+ not_saved:
11
+ one: "1 error prohibited this %{resource} from being saved:"
12
+ other: "%{count} errors prohibited this %{resource} from being saved:"
13
+
14
+ devise:
15
+ failure:
16
+ already_authenticated: 'You are already signed in.'
17
+ unauthenticated: 'You need to sign in or sign up before continuing.'
18
+ unconfirmed: 'You have to confirm your account before continuing.'
19
+ locked: 'Your account is locked.'
20
+ invalid: 'Invalid email or password.'
21
+ invalid_token: 'Invalid authentication token.'
22
+ timeout: 'Your session expired, please sign in again to continue.'
23
+ inactive: 'Your account was not activated yet.'
24
+ sessions:
25
+ signed_in: 'Signed in successfully.'
26
+ signed_out: 'Signed out successfully.'
27
+ passwords:
28
+ send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
29
+ updated: 'Your password was changed successfully. You are now signed in.'
30
+ updated_not_active: 'Your password was changed successfully.'
31
+ send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
32
+ no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
33
+ confirmations:
34
+ send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
35
+ send_paranoid_instructions: 'If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.'
36
+ confirmed: 'Your account was successfully confirmed. You are now signed in.'
37
+ registrations:
38
+ signed_up: 'Welcome! You have signed up successfully.'
39
+ signed_up_but_unconfirmed: 'A message with a confirmation link has been sent to your email address. Please open the link to activate your account.'
40
+ signed_up_but_inactive: 'You have signed up successfully. However, we could not sign you in because your account is not yet activated.'
41
+ signed_up_but_locked: 'You have signed up successfully. However, we could not sign you in because your account is locked.'
42
+ updated: 'You updated your account successfully.'
43
+ update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address."
44
+ destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
45
+ unlocks:
46
+ send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
47
+ unlocked: 'Your account has been unlocked successfully. Please sign in to continue.'
48
+ send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.'
49
+ omniauth_callbacks:
50
+ success: 'Successfully authenticated from %{kind} account.'
51
+ failure: 'Could not authenticate you from %{kind} because "%{reason}".'
52
+ mailer:
53
+ confirmation_instructions:
54
+ subject: 'Confirmation instructions'
55
+ reset_password_instructions:
56
+ subject: 'Reset password instructions'
57
+ unlock_instructions:
58
+ subject: 'Unlock Instructions'
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: "Hello world"
@@ -0,0 +1,14 @@
1
+ Dummy::Application.routes.draw do
2
+ authenticated :user do
3
+ root :to => 'home#index'
4
+ end
5
+ root :to => "home#index"
6
+ devise_for :users
7
+ resources :users do
8
+ member { post :start_session }
9
+ end
10
+
11
+ match "/cause_exception" => "home#cause_exception"
12
+ match "/report_exception" => "home#report_exception"
13
+ match "/current_user" => "home#current_user"
14
+ end
@@ -0,0 +1,46 @@
1
+ class DeviseCreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table(:users) do |t|
4
+ ## Database authenticatable
5
+ t.string :email, :null => false, :default => ""
6
+ t.string :encrypted_password, :null => false, :default => ""
7
+
8
+ ## Recoverable
9
+ t.string :reset_password_token
10
+ t.datetime :reset_password_sent_at
11
+
12
+ ## Rememberable
13
+ t.datetime :remember_created_at
14
+
15
+ ## Trackable
16
+ t.integer :sign_in_count, :default => 0
17
+ t.datetime :current_sign_in_at
18
+ t.datetime :last_sign_in_at
19
+ t.string :current_sign_in_ip
20
+ t.string :last_sign_in_ip
21
+
22
+ ## Confirmable
23
+ # t.string :confirmation_token
24
+ # t.datetime :confirmed_at
25
+ # t.datetime :confirmation_sent_at
26
+ # t.string :unconfirmed_email # Only if using reconfirmable
27
+
28
+ ## Lockable
29
+ # t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
30
+ # t.string :unlock_token # Only if unlock strategy is :email or :both
31
+ # t.datetime :locked_at
32
+
33
+ ## Token authenticatable
34
+ # t.string :authentication_token
35
+
36
+
37
+ t.timestamps
38
+ end
39
+
40
+ add_index :users, :email, :unique => true
41
+ add_index :users, :reset_password_token, :unique => true
42
+ # add_index :users, :confirmation_token, :unique => true
43
+ # add_index :users, :unlock_token, :unique => true
44
+ # add_index :users, :authentication_token, :unique => true
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ class AddNameToUsers < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :name, :string
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 20121121184654) do
15
+
16
+ create_table "users", :force => true do |t|
17
+ t.string "email", :default => "", :null => false
18
+ t.string "encrypted_password", :default => "", :null => false
19
+ t.string "reset_password_token"
20
+ t.datetime "reset_password_sent_at"
21
+ t.datetime "remember_created_at"
22
+ t.integer "sign_in_count", :default => 0
23
+ t.datetime "current_sign_in_at"
24
+ t.datetime "last_sign_in_at"
25
+ t.string "current_sign_in_ip"
26
+ t.string "last_sign_in_ip"
27
+ t.datetime "created_at", :null => false
28
+ t.datetime "updated_at", :null => false
29
+ t.string "name"
30
+ end
31
+
32
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
33
+ add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
34
+
35
+ end
@@ -0,0 +1,12 @@
1
+ # This file should contain all the record creation needed to seed the database with its default values.
2
+ # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3
+ #
4
+ # Examples:
5
+ #
6
+ # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7
+ # Mayor.create(name: 'Emanuel', city: cities.first)
8
+ puts 'SETTING UP DEFAULT USER LOGIN'
9
+ user = User.create! :name => 'First User', :email => 'user@example.com', :password => 'please', :password_confirmation => 'please'
10
+ puts 'New user created: ' << user.name
11
+ user2 = User.create! :name => 'Second User', :email => 'user2@example.com', :password => 'please', :password_confirmation => 'please'
12
+ puts 'New user created: ' << user2.name
File without changes
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe HomeController do
4
+ let(:logger_mock) { double("Rails.logger").as_null_object }
5
+
6
+ before(:each) do
7
+ reset_configuration
8
+ Rollbar.configure do |config|
9
+ config.access_token = 'aaaabbbbccccddddeeeeffff00001111'
10
+ config.environment = ::Rails.env
11
+ config.root = ::Rails.root
12
+ config.framework = "Rails: #{::Rails::VERSION::STRING}"
13
+ config.logger = logger_mock
14
+ end
15
+ end
16
+
17
+ context "with broken request" do
18
+ it "should report uncaught exceptions" do
19
+ expect{ get 'current_user', nil, :cookie => '8%B' }.to raise_exception
20
+
21
+ exception_info = Rollbar.last_report[:body][:trace][:exception]
22
+ exception_info[:class].should == 'ArgumentError'
23
+ exception_info[:message].should == 'invalid %-encoding (8%B)'
24
+ end
25
+ end
26
+
27
+ context "with error hiding deep inside" do
28
+ let!(:cookie_method_name){ :[] }
29
+ let!(:original_cookie_method){ ActionDispatch::Cookies::CookieJar.instance_method(cookie_method_name) }
30
+ let!(:broken_cookie_method){ Proc.new{ |name| "1" - 1 } }
31
+
32
+ before(:each) do
33
+ ActionDispatch::Cookies::CookieJar.send(:define_method, cookie_method_name, broken_cookie_method)
34
+ end
35
+
36
+ after(:each) do
37
+ ActionDispatch::Cookies::CookieJar.send(:define_method, cookie_method_name, original_cookie_method)
38
+ end
39
+
40
+ it "should report uncaught exceptions" do
41
+ expect{ get 'current_user' }.to raise_exception
42
+
43
+ exception_info = Rollbar.last_report[:body][:trace][:exception]
44
+ exception_info[:class].should == 'NoMethodError'
45
+ # exception_info[:message].should == 'undefined method `-\' for "1":String'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,426 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'spec_helper'
4
+
5
+ describe Rollbar do
6
+
7
+ context 'report_exception' do
8
+ before(:each) do
9
+ configure
10
+ Rollbar.configure do |config|
11
+ config.logger = logger_mock
12
+ end
13
+
14
+ begin
15
+ foo = bar
16
+ rescue => e
17
+ @exception = e
18
+ end
19
+ end
20
+
21
+ let(:logger_mock) { double("Rails.logger").as_null_object }
22
+
23
+ it 'should report exceptions without person or request data' do
24
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
25
+ Rollbar.report_exception(@exception)
26
+ end
27
+
28
+ it 'should not report anything when disabled' do
29
+ logger_mock.should_not_receive(:info).with('[Rollbar] Success')
30
+ Rollbar.configure do |config|
31
+ config.enabled = false
32
+ end
33
+
34
+ Rollbar.report_exception(@exception)
35
+
36
+ Rollbar.configure do |config|
37
+ config.enabled = true
38
+ end
39
+ end
40
+
41
+ it 'should report exceptions with request and person data' do
42
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
43
+ request_data = {
44
+ :params => { :foo => "bar" },
45
+ :url => 'http://localhost/',
46
+ :user_ip => '127.0.0.1',
47
+ :headers => {},
48
+ :GET => { "baz" => "boz" },
49
+ :session => { :user_id => 123 },
50
+ :method => "GET",
51
+ }
52
+ person_data = {
53
+ :id => 1,
54
+ :username => "test",
55
+ :email => "test@example.com"
56
+ }
57
+ Rollbar.report_exception(@exception, request_data, person_data)
58
+ end
59
+
60
+ it 'should ignore ignored exception classes' do
61
+ saved_filters = Rollbar.configuration.exception_level_filters
62
+ Rollbar.configure do |config|
63
+ config.exception_level_filters = { 'NameError' => 'ignore' }
64
+ end
65
+
66
+ logger_mock.should_not_receive(:info)
67
+ logger_mock.should_not_receive(:warn)
68
+ logger_mock.should_not_receive(:error)
69
+
70
+ Rollbar.report_exception(@exception)
71
+
72
+ Rollbar.configure do |config|
73
+ config.exception_level_filters = saved_filters
74
+ end
75
+ end
76
+
77
+ it 'should not report exceptions when silenced' do
78
+ Rollbar.should_not_receive :schedule_payload
79
+
80
+ begin
81
+ test_var = 1
82
+ Rollbar.silenced do
83
+ test_var = 2
84
+ raise
85
+ end
86
+ rescue => e
87
+ Rollbar.report_exception(e)
88
+ end
89
+
90
+ test_var.should == 2
91
+ end
92
+
93
+ it 'should report exception objects with no backtrace' do
94
+ payload = nil
95
+ Rollbar.stub(:schedule_payload) do |*args|
96
+ payload = MultiJson.load(args[0])
97
+ end
98
+ Rollbar.report_exception(StandardError.new("oops"))
99
+ payload["data"]["body"]["trace"]["frames"].should == []
100
+ payload["data"]["body"]["trace"]["exception"]["class"].should == "StandardError"
101
+ payload["data"]["body"]["trace"]["exception"]["message"].should == "oops"
102
+ end
103
+
104
+ it 'should return the exception data with a uuid, on platforms with SecureRandom' do
105
+ if defined?(SecureRandom) and SecureRandom.respond_to?(:uuid)
106
+ Rollbar.stub(:schedule_payload) do |*args| end
107
+ exception_data = Rollbar.report_exception(StandardError.new("oops"))
108
+ exception_data[:uuid].should_not be_nil
109
+ end
110
+ end
111
+ end
112
+
113
+ context 'report_message' do
114
+ before(:each) do
115
+ configure
116
+ Rollbar.configure do |config|
117
+ config.logger = logger_mock
118
+ end
119
+ end
120
+
121
+ let(:logger_mock) { double("Rails.logger").as_null_object }
122
+
123
+ it 'should report simple messages' do
124
+ logger_mock.should_receive(:info).with('[Rollbar] Scheduling payload')
125
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
126
+ Rollbar.report_message("Test message")
127
+ end
128
+
129
+ it 'should not report anything when disabled' do
130
+ logger_mock.should_not_receive(:info).with('[Rollbar] Success')
131
+ Rollbar.configure do |config|
132
+ config.enabled = false
133
+ end
134
+
135
+ Rollbar.report_message("Test message that should be ignored")
136
+
137
+ Rollbar.configure do |config|
138
+ config.enabled = true
139
+ end
140
+ end
141
+
142
+ it 'should report messages with extra data' do
143
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
144
+ Rollbar.report_message("Test message with extra data", 'debug', :foo => "bar",
145
+ :hash => { :a => 123, :b => "xyz" })
146
+ end
147
+
148
+ it 'should not crash with circular extra_data' do
149
+ a = { :foo => "bar" }
150
+ b = { :a => a }
151
+ c = { :b => b }
152
+ a[:c] = c
153
+
154
+ logger_mock.should_receive(:error).with(/\[Rollbar\] Error reporting message to Rollbar: (nesting of \d+ is too deep|object references itself)/)
155
+ Rollbar.report_message("Test message with circular extra data", 'debug', a)
156
+ end
157
+
158
+ after(:each) do
159
+ Rollbar.configure do |config|
160
+ config.logger = ::Rails.logger
161
+ end
162
+ end
163
+ end
164
+
165
+ context 'payload_destination' do
166
+ before(:each) do
167
+ configure
168
+ Rollbar.configure do |config|
169
+ config.logger = logger_mock
170
+ config.filepath = 'test.rollbar'
171
+ end
172
+
173
+ begin
174
+ foo = bar
175
+ rescue => e
176
+ @exception = e
177
+ end
178
+ end
179
+
180
+ let(:logger_mock) { double("Rails.logger").as_null_object }
181
+
182
+ it 'should send the payload over the network by default' do
183
+ logger_mock.should_not_receive(:info).with('[Rollbar] Writing payload to file')
184
+ logger_mock.should_receive(:info).with('[Rollbar] Sending payload')
185
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
186
+ Rollbar.report_exception(@exception)
187
+ end
188
+
189
+ it 'should save the payload to a file if set' do
190
+ logger_mock.should_not_receive(:info).with('[Rollbar] Sending payload')
191
+ logger_mock.should_receive(:info).with('[Rollbar] Writing payload to file')
192
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
193
+
194
+ filepath = ''
195
+
196
+ Rollbar.configure do |config|
197
+ config.write_to_file = true
198
+ filepath = config.filepath
199
+ end
200
+
201
+ Rollbar.report_exception(@exception)
202
+
203
+ File.exist?(filepath).should == true
204
+ File.read(filepath).should include test_access_token
205
+ File.delete(filepath)
206
+
207
+ Rollbar.configure do |config|
208
+ config.write_to_file = false
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'asynchronous_handling' do
214
+ before(:each) do
215
+ configure
216
+ Rollbar.configure do |config|
217
+ config.logger = logger_mock
218
+ end
219
+
220
+ begin
221
+ foo = bar
222
+ rescue => e
223
+ @exception = e
224
+ end
225
+ end
226
+
227
+ let(:logger_mock) { double("Rails.logger").as_null_object }
228
+
229
+ it 'should send the payload using the default asynchronous handler girl_friday' do
230
+ logger_mock.should_receive(:info).with('[Rollbar] Scheduling payload')
231
+ logger_mock.should_receive(:info).with('[Rollbar] Sending payload')
232
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
233
+
234
+ Rollbar.configure do |config|
235
+ config.use_async = true
236
+ GirlFriday::WorkQueue::immediate!
237
+ end
238
+
239
+ Rollbar.report_exception(@exception)
240
+
241
+ Rollbar.configure do |config|
242
+ config.use_async = false
243
+ GirlFriday::WorkQueue::queue!
244
+ end
245
+ end
246
+
247
+ it 'should send the payload using a user-supplied asynchronous handler' do
248
+ logger_mock.should_receive(:info).with('Custom async handler called')
249
+ logger_mock.should_receive(:info).with('[Rollbar] Sending payload')
250
+ logger_mock.should_receive(:info).with('[Rollbar] Success')
251
+
252
+ Rollbar.configure do |config|
253
+ config.use_async = true
254
+ config.async_handler = Proc.new { |payload|
255
+ logger_mock.info 'Custom async handler called'
256
+ Rollbar.process_payload(payload)
257
+ }
258
+ end
259
+
260
+ Rollbar.report_exception(@exception)
261
+
262
+ Rollbar.configure do |config|
263
+ config.use_async = false
264
+ config.async_handler = Rollbar.method(:default_async_handler)
265
+ end
266
+ end
267
+ end
268
+
269
+ context 'message_data' do
270
+ before(:each) do
271
+ configure
272
+ @message_body = "This is a test"
273
+ @level = 'debug'
274
+ end
275
+
276
+ it 'should build a message' do
277
+ data = Rollbar.send(:message_data, @message_body, @level, {})
278
+ data[:body][:message][:body].should == @message_body
279
+ data[:level].should == @level
280
+ end
281
+
282
+ it 'should accept extra_data' do
283
+ user_id = 123
284
+ name = "Tester"
285
+
286
+ data = Rollbar.send(:message_data, @message_body, 'info',
287
+ :user_id => user_id, :name => name)
288
+
289
+ message = data[:body][:message]
290
+ message[:body].should == @message_body
291
+ message[:user_id].should == user_id
292
+ message[:name].should == name
293
+ end
294
+ end
295
+
296
+ context 'exception_data' do
297
+ before(:each) do
298
+ configure
299
+ begin
300
+ foo = bar
301
+ rescue => e
302
+ @exception = e
303
+ end
304
+ end
305
+
306
+ it 'should accept force_level' do
307
+ level = 'critical'
308
+ data = Rollbar.send(:exception_data, @exception, level)
309
+ data[:level].should == level
310
+ end
311
+
312
+ it 'should build valid exception data' do
313
+ data = Rollbar.send(:exception_data, @exception)
314
+
315
+ data[:level].should_not be_nil
316
+
317
+ trace = data[:body][:trace]
318
+
319
+ frames = trace[:frames]
320
+ frames.should be_a_kind_of(Array)
321
+ frames.each do |frame|
322
+ frame[:filename].should be_a_kind_of(String)
323
+ frame[:lineno].should be_a_kind_of(Fixnum)
324
+ if frame[:method]
325
+ frame[:method].should be_a_kind_of(String)
326
+ end
327
+ end
328
+
329
+ # should be NameError, but can be NoMethodError sometimes on rubinius 1.8
330
+ # http://yehudakatz.com/2010/01/02/the-craziest-fing-bug-ive-ever-seen/
331
+ trace[:exception][:class].should match(/^(NameError|NoMethodError)$/)
332
+ trace[:exception][:message].should match(/^(undefined local variable or method `bar'|undefined method `bar' on an instance of)/)
333
+ end
334
+ end
335
+
336
+ context 'logger' do
337
+ before(:each) do
338
+ reset_configuration
339
+ end
340
+
341
+ it 'should have use the Rails logger when configured to do so' do
342
+ configure
343
+ Rollbar.send(:logger).should == ::Rails.logger
344
+ end
345
+
346
+ it 'should use the default_logger when no logger is set' do
347
+ logger = Logger.new(STDERR)
348
+ Rollbar.configure do |config|
349
+ config.default_logger = lambda { logger }
350
+ end
351
+ Rollbar.send(:logger).should == logger
352
+ end
353
+
354
+ it 'should have a default default_logger' do
355
+ Rollbar.send(:logger).should_not be_nil
356
+ end
357
+
358
+ after(:each) do
359
+ reset_configuration
360
+ end
361
+ end
362
+
363
+ context 'build_payload' do
364
+ it 'should build valid json' do
365
+ json = Rollbar.send(:build_payload, {:foo => {:bar => "baz"}})
366
+ hash = MultiJson.load(json)
367
+ hash["data"]["foo"]["bar"].should == "baz"
368
+ end
369
+ end
370
+
371
+ context 'base_data' do
372
+ before(:each) { configure }
373
+
374
+ it 'should have the correct notifier name' do
375
+ Rollbar.send(:base_data)[:notifier][:name].should == 'rollbar-gem'
376
+ end
377
+
378
+ it 'should have the correct notifier version' do
379
+ Rollbar.send(:base_data)[:notifier][:version].should == Rollbar::VERSION
380
+ end
381
+
382
+ it 'should have all the required keys' do
383
+ data = Rollbar.send(:base_data)
384
+ data[:timestamp].should_not be_nil
385
+ data[:environment].should_not be_nil
386
+ data[:level].should_not be_nil
387
+ data[:language].should == 'ruby'
388
+ data[:framework].should match(/^Rails/)
389
+ end
390
+ end
391
+
392
+ context 'server_data' do
393
+ it 'should have the right hostname' do
394
+ Rollbar.send(:server_data)[:host] == Socket.gethostname
395
+ end
396
+
397
+ it 'should have root and branch set when configured' do
398
+ configure
399
+ Rollbar.configure do |config|
400
+ config.root = '/path/to/root'
401
+ config.branch = 'master'
402
+ end
403
+
404
+ data = Rollbar.send(:server_data)
405
+ data[:root].should == '/path/to/root'
406
+ data[:branch].should == 'master'
407
+ end
408
+ end
409
+
410
+ # configure with some basic params
411
+ def configure
412
+ Rollbar.configure do |config|
413
+ # special test access token
414
+ config.access_token = test_access_token
415
+ config.logger = ::Rails.logger
416
+ config.environment = ::Rails.env
417
+ config.root = ::Rails.root
418
+ config.framework = "Rails: #{::Rails::VERSION::STRING}"
419
+ end
420
+ end
421
+
422
+ def test_access_token
423
+ 'aaaabbbbccccddddeeeeffff00001111'
424
+ end
425
+
426
+ end