├── .codeclimate.yml ├── .github ├── pull_request_template.md └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .rubocop.yml ├── Appraisals ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── THANKS.md ├── UPGRADE_FROM_RATCHET.md ├── UPGRADING.md ├── bin └── rollbar-rails-runner ├── data └── rollbar.snippet.js ├── docs ├── configuration.md └── plugins.md ├── gemfiles ├── rails50.gemfile ├── rails51.gemfile ├── rails52.gemfile ├── rails60.gemfile ├── rails61.gemfile ├── rails70.gemfile └── rails71.gemfile ├── lib ├── generators │ └── rollbar │ │ ├── rollbar_generator.rb │ │ └── templates │ │ └── initializer.erb ├── rails │ └── rollbar_runner.rb ├── rollbar.rb ├── rollbar │ ├── capistrano.rb │ ├── capistrano3.rb │ ├── capistrano_tasks.rb │ ├── configuration.rb │ ├── delay │ │ ├── active_job.rb │ │ ├── delayed_job.rb │ │ ├── girl_friday.rb │ │ ├── resque.rb │ │ ├── shoryuken.rb │ │ ├── sidekiq.rb │ │ ├── sucker_punch.rb │ │ └── thread.rb │ ├── deploy.rb │ ├── encoding.rb │ ├── encoding │ │ └── encoder.rb │ ├── exception_reporter.rb │ ├── exceptions.rb │ ├── item.rb │ ├── item │ │ ├── backtrace.rb │ │ ├── frame.rb │ │ └── locals.rb │ ├── js.rb │ ├── json.rb │ ├── language_support.rb │ ├── lazy_store.rb │ ├── logger.rb │ ├── logger_proxy.rb │ ├── middleware │ │ ├── js.rb │ │ ├── js │ │ │ └── json_value.rb │ │ ├── rack.rb │ │ ├── rack │ │ │ ├── builder.rb │ │ │ └── test_session.rb │ │ ├── rails │ │ │ ├── rollbar.rb │ │ │ └── show_exceptions.rb │ │ └── sinatra.rb │ ├── notifier.rb │ ├── notifier │ │ └── trace_with_bindings.rb │ ├── plugin.rb │ ├── plugins.rb │ ├── plugins │ │ ├── active_job.rb │ │ ├── basic_socket.rb │ │ ├── delayed_job.rb │ │ ├── delayed_job │ │ │ ├── job_data.rb │ │ │ └── plugin.rb │ │ ├── error_context.rb │ │ ├── goalie.rb │ │ ├── rack.rb │ │ ├── rails.rb │ │ ├── rails │ │ │ ├── controller_methods.rb │ │ │ ├── error_subscriber.rb │ │ │ ├── railtie30.rb │ │ │ ├── railtie32.rb │ │ │ └── railtie_mixin.rb │ │ ├── rake.rb │ │ ├── resque.rb │ │ ├── resque │ │ │ └── failure.rb │ │ ├── sidekiq.rb │ │ ├── sidekiq │ │ │ └── plugin.rb │ │ ├── thread.rb │ │ └── validations.rb │ ├── rails.rb │ ├── rake_tasks.rb │ ├── request_data_extractor.rb │ ├── rollbar_test.rb │ ├── scrubbers.rb │ ├── scrubbers │ │ ├── params.rb │ │ └── url.rb │ ├── truncation.rb │ ├── truncation │ │ ├── frames_strategy.rb │ │ ├── min_body_strategy.rb │ │ ├── mixin.rb │ │ ├── raw_strategy.rb │ │ ├── remove_any_key_strategy.rb │ │ ├── remove_extra_strategy.rb │ │ ├── remove_request_strategy.rb │ │ └── strings_strategy.rb │ ├── util.rb │ ├── util │ │ ├── hash.rb │ │ ├── ip_anonymizer.rb │ │ └── ip_obfuscator.rb │ └── version.rb └── tasks │ ├── benchmark.rake │ └── tasks.rake ├── rollbar.gemspec └── spec ├── commands └── rollbar_rails_runner_spec.rb ├── controllers └── home_controller_spec.rb ├── delay ├── sidekiq_spec.rb └── sucker_punch_spec.rb ├── delayed ├── backend │ └── test.rb └── serialization │ └── test.rb ├── dummyapp ├── .gitignore ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css.scss │ ├── controllers │ │ ├── application_controller.rb │ │ ├── home_controller.rb │ │ └── users_controller.rb │ ├── helpers │ │ └── .gitkeep │ ├── mailers │ │ └── .gitkeep │ ├── models │ │ ├── .gitkeep │ │ ├── book.rb │ │ ├── post.rb │ │ └── user.rb │ └── views │ │ ├── devise │ │ ├── registrations │ │ │ ├── edit.html.erb │ │ │ └── new.html.erb │ │ └── shared │ │ │ └── _links.html.erb │ │ ├── home │ │ ├── cause_exception.html.erb │ │ ├── index.html.erb │ │ └── report_exception.html.erb │ │ ├── js │ │ └── test.html.erb │ │ ├── layouts │ │ ├── _messages.html.erb │ │ ├── _navigation.html.erb │ │ ├── application.html.erb │ │ └── simple.html.erb │ │ └── users │ │ ├── index.html.erb │ │ └── show.html.erb ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── backtrace_silencers.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── rollbar.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ ├── devise.en.yml │ │ └── en.yml │ ├── routes.rb │ ├── secrets.yml │ └── storage.yml ├── db │ ├── migrate │ │ ├── 20121121184652_devise_create_users.rb │ │ ├── 20121121184654_add_name_to_users.rb │ │ ├── 20161219184410_create_books.rb │ │ └── 20161219185529_add_username_to_users.rb │ ├── schema.rb │ └── seeds.rb ├── lib │ └── assets │ │ └── .gitkeep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ └── favicon.ico └── script │ └── rails ├── fixtures ├── file1 ├── file2 ├── payloads │ ├── message.json │ ├── sample.trace.json │ └── sample.trace_chain.json └── plugins │ ├── dummy1.rb │ └── dummy2.rb ├── generators └── rollbar │ ├── rollbar_generator_rails30_spec.rb │ └── rollbar_generator_spec.rb ├── requests └── home_spec.rb ├── rollbar ├── capistrano_tasks_spec.rb ├── configuration_spec.rb ├── delay │ ├── active_job_spec.rb │ ├── delayed_job_spec.rb │ ├── girl_friday_spec.rb │ ├── resque_spec.rb │ ├── shoryuken_spec.rb │ └── thread_spec.rb ├── deploy_spec.rb ├── encoding │ └── encoder_spec.rb ├── item │ ├── backtrace_spec.rb │ └── frame_spec.rb ├── item_spec.rb ├── json_spec.rb ├── lazy_store_spec.rb ├── logger_proxy_spec.rb ├── logger_spec.rb ├── middleware │ ├── js_spec.rb │ ├── rack_spec.rb │ └── sinatra_spec.rb ├── notifier_spec.rb ├── plugin_spec.rb ├── plugins │ ├── active_job_spec.rb │ ├── basic_socket_spec.rb │ ├── delayed_job │ │ └── job_data_spec.rb │ ├── delayed_job_spec.rb │ ├── rack_spec.rb │ ├── rails_js_spec.rb │ ├── rake_spec.rb │ ├── resque │ │ └── failure_spec.rb │ ├── sidekiq_spec.rb │ ├── thread_spec.rb │ └── validations_spec.rb ├── plugins_spec.rb ├── rake_tasks_spec.rb ├── request_data_extractor_spec.rb ├── scrubbers │ ├── params_spec.rb │ └── url_spec.rb ├── scrubbers_spec.rb ├── sidekiq │ └── reset_scope_spec.rb ├── truncation │ ├── frames_strategy_spec.rb │ ├── min_body_strategy_spec.rb │ ├── remove_any_key_strategy_spec.rb │ ├── remove_extra_strategy_spec.rb │ ├── remove_request_strategy_spec.rb │ └── strings_strategy_spec.rb ├── truncation_spec.rb ├── util │ ├── hash_spec.rb │ └── ip_anonymizer_spec.rb └── util_spec.rb ├── rollbar_bc_spec.rb ├── rollbar_spec.rb ├── spec_helper.rb └── support ├── cause_exception.rb ├── deploy_api ├── report.rb └── update.rb ├── encoding_helpers.rb ├── encodings └── iso_8859_9 ├── fixture_helpers.rb ├── get_ip_raising.rb ├── helpers.rb ├── matchers.rb ├── mock_app.rb ├── notifier_helpers.rb ├── rollbar_api.rb ├── secure_headers.rb ├── secure_headers_mocks.rb └── shared_contexts.rb /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - ruby 8 | eslint: 9 | enabled: false 10 | fixme: 11 | enabled: true 12 | rubocop: 13 | enabled: true 14 | ratings: 15 | paths: 16 | - "**.rb" 17 | exclude_paths: 18 | - spec/ 19 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description of the change 2 | 3 | > Please include a summary of the change and which issues are fixed. 4 | > Please also include relevant motivation and context. 5 | 6 | ## Type of change 7 | 8 | - [ ] Bug fix (non-breaking change that fixes an issue) 9 | - [ ] New feature (non-breaking change that adds functionality) 10 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 11 | - [ ] Maintenance 12 | - [ ] New release 13 | 14 | ## Related issues 15 | 16 | > Shortcut stories and GitHub issues (delete irrelevant) 17 | 18 | - Fix [SC-] 19 | - Fix #1 20 | 21 | ## Checklists 22 | 23 | ### Development 24 | 25 | - [ ] Lint rules pass locally 26 | - [ ] The code changed/added as part of this pull request has been covered with tests 27 | - [ ] All tests related to the changed code pass in development 28 | 29 | ### Code review 30 | 31 | - [ ] This pull request has a descriptive title and information useful to a reviewer. There may be a screenshot or screencast attached 32 | - [ ] "Ready for review" label attached to the PR and reviewers assigned 33 | - [ ] Issue from task tracker has a link to this pull request 34 | - [ ] Changes have been reviewed by at least one other engineer 35 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Rollbar-gem CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | matrix: 14 | ruby-version: [2.5.3, 2.6.0, 2.6.6, 2.7.2] 15 | gemfile: 16 | - gemfiles/rails50.gemfile 17 | - gemfiles/rails51.gemfile 18 | - gemfiles/rails52.gemfile 19 | - gemfiles/rails60.gemfile 20 | - gemfiles/rails61.gemfile 21 | include: 22 | - gemfile: gemfiles/rails71.gemfile 23 | ruby-version: 3.4.1 24 | - gemfile: gemfiles/rails71.gemfile 25 | ruby-version: 3.2.2 26 | - gemfile: gemfiles/rails71.gemfile 27 | ruby-version: 3.1.1 28 | - gemfile: gemfiles/rails70.gemfile 29 | ruby-version: 3.1.1 30 | - gemfile: gemfiles/rails70.gemfile 31 | ruby-version: 3.0.3 32 | - gemfile: gemfiles/rails61.gemfile 33 | ruby-version: 3.0.3 34 | 35 | steps: 36 | - uses: actions/checkout@v2 37 | with: 38 | submodules: recursive 39 | 40 | - name: Start Redis 41 | uses: supercharge/redis-github-action@1.1.0 42 | with: 43 | redis-version: 4 44 | 45 | - name: Setup Ruby > 2.0 46 | uses: ruby/setup-ruby@v1 47 | if: ${{ matrix.ruby-version != '2.0.0' }} 48 | with: 49 | ruby-version: ${{ matrix.ruby-version }} 50 | 51 | - name: Rails 4.2 ensure bundler version 52 | if: ${{ matrix.gemfile == 'gemfiles/rails42.gemfile' }} 53 | run: | 54 | gem uninstall bundler 55 | gem install bundler -v '< 2.0.0' 56 | 57 | - name: Bundle Install 58 | run: | 59 | export BUNDLE_GEMFILE=${{ matrix.gemfile }} 60 | bundle config path vendor/bundle 61 | bundle config gemfile ${{ matrix.gemfile }} 62 | bundle install --jobs 4 --retry 3 63 | 64 | - name: Rspec 65 | run: | 66 | export BUNDLE_GEMFILE=${{ matrix.gemfile }} 67 | bundle config path vendor/bundle 68 | bundle config gemfile ${{ matrix.gemfile }} 69 | bundle exec rspec 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | gemfiles/*.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | log/ 13 | lib/bundler/man 14 | vendor/bundle 15 | pkg 16 | rdoc 17 | spec/reports 18 | test/tmp 19 | test/version_tmp 20 | tmp 21 | *.swp 22 | .idea/ 23 | .ruby-version 24 | .byebug_history 25 | 26 | gemfiles/vendor 27 | 28 | vendor -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rollbar.js"] 2 | path = rollbar.js 3 | url = https://github.com/rollbar/rollbar.js.git 4 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise 'rails30' do 2 | gem 'rails', '3.0.20' 3 | end 4 | 5 | appraise 'rails31' do 6 | gem 'rails', '3.1.12' 7 | end 8 | 9 | appraise 'rails32' do 10 | gem 'rails', '3.2.21' 11 | end 12 | 13 | appraise 'rails40' do 14 | gem 'rails', '4.0.13' 15 | end 16 | 17 | appraise 'rails41' do 18 | gem 'rails', '4.1.9' 19 | end 20 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # This Gemfile is compatible with Ruby 2.5.0 or greater. To test with 2 | # earlier Rubies, use the appropriate Gemfile from the ./gemfiles/ dir. 3 | ruby '3.4.1' 4 | 5 | source 'https://rubygems.org' 6 | 7 | # Used by spec/commands/rollbar_rails_runner_spec, and can be used whenever a 8 | # new process is created during tests. (Testing rake tasks, for example.) 9 | # This is a workaround for ENV['BUNDLE_GEMFILE'] not working as expected on Travis. 10 | # We use the ||= assignment because Travis loads the gemfile twice, the second time 11 | # with the wrong gemfile path. 12 | ENV['CURRENT_GEMFILE'] ||= __FILE__ 13 | 14 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 15 | 16 | GEMFILE_RAILS_VERSION = '~> 7.1.0'.freeze 17 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 18 | gem 'appraisal' 19 | gem 'jruby-openssl', :platform => :jruby 20 | gem 'rails', GEMFILE_RAILS_VERSION 21 | gem 'rake' 22 | if GEMFILE_RAILS_VERSION < '6.0' 23 | gem 'rspec-rails', '~> 3.4' 24 | elsif GEMFILE_RAILS_VERSION < '7.0' 25 | gem 'rspec-rails', '~> 4.0.2' 26 | else 27 | gem 'rspec-rails', '~> 6.0.3' 28 | end 29 | 30 | if GEMFILE_RAILS_VERSION < '7.1' 31 | gem 'concurrent-ruby', '1.3.4' 32 | end 33 | 34 | if GEMFILE_RAILS_VERSION < '6.0' 35 | gem 'sqlite3', '< 1.4.0', :platform => [:ruby, :mswin, :mingw] 36 | else 37 | gem 'sqlite3', '~> 1.4', :platform => [:ruby, :mswin, :mingw] 38 | end 39 | 40 | gem 'sidekiq', '>= 6.4.0' 41 | 42 | platforms :rbx do 43 | gem 'minitest' 44 | gem 'racc' 45 | gem 'rubinius-developer_tools' 46 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 47 | end 48 | 49 | gem 'capistrano', :require => false 50 | gem 'shoryuken' 51 | gem 'simplecov' 52 | gem 'sucker_punch', '~> 2.0' 53 | 54 | unless is_jruby 55 | # JRuby doesn't support fork, which is required for this test helper. 56 | gem 'rspec-command' 57 | end 58 | 59 | gem 'aws-sdk-sqs' 60 | 61 | if GEMFILE_RAILS_VERSION >= '5.2' 62 | gem 'database_cleaner' 63 | elsif GEMFILE_RAILS_VERSION.between?('5.0', '5.2') 64 | gem 'database_cleaner', '~> 1.8.4' 65 | elsif GEMFILE_RAILS_VERSION < '5.0' 66 | gem 'database_cleaner', '~> 1.0.0' 67 | end 68 | 69 | if GEMFILE_RAILS_VERSION < '6.0' 70 | gem 'delayed_job', :require => false 71 | else 72 | gem 'delayed_job', '~> 4.1', :require => false 73 | end 74 | gem 'generator_spec' 75 | gem 'redis', '<= 4.8.0' 76 | gem 'resque', '< 2.0.0' 77 | gem 'rubocop', '1.15.0', :require => false # pin specific version, update manually 78 | gem 'rubocop-performance', :require => false 79 | gem 'secure_headers', '~> 6.3.2', :require => false 80 | gem 'sinatra' 81 | gem 'webmock', :require => false 82 | gemspec 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 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. 23 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require 'rubygems' 3 | require 'bundler/setup' 4 | require 'bundler/gem_tasks' 5 | require 'rspec/core/rake_task' 6 | require 'appraisal' 7 | 8 | RSpec::Core::RakeTask.new(:spec) 9 | 10 | desc 'Run specs' 11 | task :default do 12 | ENV['LOCAL'] = '1' 13 | Rake::Task[:spec].invoke 14 | 15 | Rake::Task[:spec].reenable 16 | 17 | ENV['LOCAL'] = '0' 18 | Rake::Task[:spec].invoke 19 | end 20 | 21 | Dir.glob('lib/tasks/*.rake').each { |r| load r } 22 | -------------------------------------------------------------------------------- /THANKS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | Huge thanks to the following contributors (by github username). For the most up-to-date list, see https://github.com/rollbar/rollbar-gem/graphs/contributors 4 | 5 | - [alexdunae](https://github.com/alexdunae) 6 | - [allspiritseve](https://github.com/allspiritseve) 7 | - [antico5](https://github.com/antico5) 8 | - [arr-ee](https://github.com/arr-ee) 9 | - [awmichel](https://github.com/awmichel) 10 | - [blaet](https://github.com/blaet) 11 | - [bradx3](https://github.com/bradx3) 12 | - [chrisb](https://github.com/chrisb) 13 | - [derekrockwell](https://github.com/derekrockwell) 14 | - [dimko](https://github.com/dimko) 15 | - [dlackty](https://github.com/dlackty) 16 | - [fab](https://github.com/fab) 17 | - [firstbanco](https://github.com/firstbanco) 18 | - [flomotlik](https://github.com/flomotlik) 19 | - [Florent2](https://github.com/Florent2) 20 | - [gdeglin](https://github.com/gdeglin) 21 | - [gersmann](https://github.com/gersmann) 22 | - [grosser](https://github.com/grosser) 23 | - [GUI](https://github.com/GUI) 24 | - [ixti](https://github.com/ixti) 25 | - [jeremyvdw](https://github.com/jeremyvdw) 26 | - [jjb](https://github.com/jjb) 27 | - [johnknott](https://github.com/johnknott) 28 | - [johnsyweb](https://github.com/johnsyweb) 29 | - [jonah-williams](https://github.com/jonah-williams) 30 | - [jondeandres](https://github.com/jondeandres) 31 | - [JoshuaOSHickman](https://github.com/JoshuaOSHickman) 32 | - [juggler](https://github.com/juggler) 33 | - [kavu](https://github.com/kavu) 34 | - [kdonovan](https://github.com/kdonovan) 35 | - [kroky](https://github.com/kroky) 36 | - [lanej](https://github.com/lanej) 37 | - [lesliev-figured](https://github.com/lesliev-figured) 38 | - [magnolia-fan](https://github.com/magnolia-fan) 39 | - [mauricio](https://github.com/mauricio) 40 | - [metaskills](https://github.com/metaskills) 41 | - [miloops](https://github.com/miloops) 42 | - [mipearson](https://github.com/mipearson) 43 | - [mrgordon](https://github.com/mrgordon) 44 | - [nikolai-b](https://github.com/nikolai-b) 45 | - [notahat](https://github.com/notahat) 46 | - [pedro](https://github.com/pedro) 47 | - [petergoldstein](https://github.com/petergoldstein) 48 | - [pmen](https://github.com/pmen) 49 | - [rogercampos](https://github.com/rogercampos) 50 | - [siong1987](https://github.com/siong1987) 51 | - [trisweb](https://github.com/trisweb) 52 | - [tysontate](https://github.com/tysontate) 53 | - [vyrak](https://github.com/vyrak) 54 | - [wbond](https://github.com/wbond) 55 | -------------------------------------------------------------------------------- /UPGRADE_FROM_RATCHET.md: -------------------------------------------------------------------------------- 1 | # Upgrading from ratchetio-gem 2 | 3 | ## Required immediate steps 4 | 5 | Add this line to your application's Gemfile: 6 | 7 | gem 'rollbar', '~> 0.10.3' 8 | 9 | And remove: 10 | 11 | gem 'ratchetio' 12 | 13 | Then execute: 14 | 15 | $ bundle install 16 | 17 | Next, rename your `config/initializers/ratchetio.rb` to `config/initializers/rollbar.rb` 18 | 19 | Open `config/initializers/rollbar.rb` and change `require 'ratchetio/rails'` to `require 'rollbar/rails'` 20 | 21 | At this point the new Rollbar library should be properly integrated and begin to report exceptions to Rollbar. 22 | 23 | ## Optional steps 24 | 25 | These are not required because aliases have been set up from the Ratchetio module/functions to the respective Rollbar versions. 26 | 27 | Replace all instances of `Ratchetio` in your rails app with `Rollbar`. 28 | 29 | Replace all instances of `ratchetio_request_data` with `rollbar_request_data`. 30 | 31 | Replace all instances of `ratchetio_person_data` with `rollbar_person_data`. 32 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrading 2 | 3 | ## From 1.1.0 or lower to 1.2.0 4 | 5 | The public interface has been rewritten entirely in 1.2.0 to be more versatile and in-line with the new interface established recently in rollbar.js. The main `#report_message` and `#report_exception` methods are now deprecated in favor of the new `#log`, `#debug` `#info`, `#warn`, `#error` and `#critical` methods. 6 | 7 | The new methods will accept any number of arguments. The last string argument is used as a message/description, the last exception argument is used as the reported exception, and the last hash is used as the extra data (except for `log` which requires an additional level string as the first argument). 8 | 9 | The old methods will still function properly but it is recommended to migrate to the new interface whenever possible. You can migrate simply by doing the following: 10 | 11 | 1. Replace all occurrences of `#report_exception` with `#error`, or `#log` with a custom level if set in your existing `#report_exception` call. 12 | 13 | 2. Replace all occurrences of `#report_message` and `#report_message_with_request` with the one of the logging methods `#debug` through `#critical`. 14 | 15 | 3. The argument order can stay the same. 16 | 17 | If using a Rack application, `request_data` and `person_data` will not longer be required to be passed in when logging messages or exceptions. The Rack, Sinatra or Rails middleware is responsible to extract the data and pass it to Rollbar. 18 | 19 | If **not** using any Rack application, then you will need to use the `#scope` or `#scoped` method to set this data manually: 20 | 21 | ```ruby 22 | notifier = Rollbar.scope({ 23 | :request => rollbar_request_data, 24 | :person => rollbar_person_data 25 | }) 26 | 27 | # will contain request parameters and person data 28 | notifier.warning('User submitted invalid form data') 29 | ``` 30 | 31 | The `#scoped`method allows to change the payload options for a specific code block. This is the method used by the Rack and Rails middlewares. 32 | 33 | ```ruby 34 | scope = { :request => rollbar_request_data, 35 | :person => rollbar_person_data 36 | } 37 | 38 | Rollbar.scoped(scope) do 39 | begin 40 | # code that will raise 41 | rescue => e 42 | Rollbar.error(e) 43 | end 44 | end 45 | ``` 46 | -------------------------------------------------------------------------------- /bin/rollbar-rails-runner: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'rails/rollbar_runner' 4 | 5 | Rails::RollbarRunner.new.run 6 | -------------------------------------------------------------------------------- /gemfiles/rails50.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'net-ssh', '<= 3.1.1' 10 | gem 'public_suffix', '<= 3.1.1' 11 | gem 'rails', '~> 5.0.7' 12 | gem 'sqlite3', '< 1.4.0', :platform => [:ruby, :mswin, :mingw] 13 | 14 | gem 'rspec-core', '~> 3.5.0.beta3' 15 | gem 'rspec-expectations', '~> 3.5.0.beta3' 16 | gem 'rspec-mocks', '~> 3.5.0.beta3' 17 | gem 'rspec-rails', '~> 3.5.0.beta3' 18 | gem 'rspec-support', '~> 3.5.0.beta3' 19 | 20 | gem 'rake' 21 | 22 | gem 'sidekiq', '>= 2.13.0' 23 | 24 | platforms :rbx do 25 | gem 'minitest' 26 | gem 'racc' 27 | gem 'rubinius-developer_tools' 28 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 29 | end 30 | 31 | gem 'capistrano', :require => false 32 | gem 'simplecov', '<= 0.17.1' 33 | gem 'sucker_punch', '~> 2.0' 34 | 35 | gem 'rack', '2.1.2' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') 36 | 37 | gem 'concurrent-ruby', '1.3.4' 38 | gem 'database_cleaner', '~> 1.8.4' 39 | gem 'delayed_job', :require => false 40 | gem 'generator_spec' 41 | gem 'redis', '<= 3.3.5' 42 | gem 'resque' 43 | gem 'secure_headers', '~> 6.3.2', :require => false 44 | 45 | # We need last sinatra that uses rack 2.1.x 46 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag => 'v2.0.8' 47 | 48 | unless is_jruby 49 | # JRuby doesn't support fork, which is required for this test helper. 50 | gem 'rspec-command' 51 | end 52 | 53 | gem 'webmock', :require => false 54 | 55 | gem 'aws-sdk-sqs' 56 | gem 'shoryuken' 57 | 58 | gemspec :path => '../' 59 | -------------------------------------------------------------------------------- /gemfiles/rails51.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'net-ssh', '<= 3.1.1' 10 | gem 'public_suffix', '<= 3.1.1' 11 | gem 'rails', '~> 5.1.7' 12 | gem 'sqlite3', '< 1.4.0', :platform => [:ruby, :mswin, :mingw] 13 | 14 | gem 'rspec-core', '~> 3.5.0.beta3' 15 | gem 'rspec-expectations', '~> 3.5.0.beta3' 16 | gem 'rspec-mocks', '~> 3.5.0.beta3' 17 | gem 'rspec-rails', '~> 3.5.0.beta3' 18 | gem 'rspec-support', '~> 3.5.0.beta3' 19 | 20 | gem 'rake' 21 | 22 | gem 'sidekiq', '>= 2.13.0' 23 | 24 | platforms :rbx do 25 | gem 'minitest' 26 | gem 'racc' 27 | gem 'rubinius-developer_tools' 28 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 29 | end 30 | 31 | gem 'capistrano', :require => false 32 | gem 'simplecov', '<= 0.17.1' 33 | gem 'sucker_punch', '~> 2.0' 34 | 35 | gem 'rack', '2.1.2' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') 36 | 37 | # We need last sinatra that uses rack 2.1.x 38 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag => 'v2.0.8' 39 | 40 | gem 'concurrent-ruby', '1.3.4' 41 | gem 'database_cleaner', '~> 1.8.4' 42 | gem 'delayed_job', :require => false 43 | gem 'generator_spec' 44 | gem 'redis', '<= 3.3.5' 45 | gem 'resque' 46 | gem 'secure_headers', '~> 6.3.2', :require => false 47 | 48 | unless is_jruby 49 | # JRuby doesn't support fork, which is required for this test helper. 50 | gem 'rspec-command' 51 | end 52 | 53 | gem 'webmock', :require => false 54 | 55 | gem 'aws-sdk-sqs' 56 | gem 'shoryuken' 57 | 58 | gemspec :path => '../' 59 | -------------------------------------------------------------------------------- /gemfiles/rails52.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'rails', '~> 5.2.3' 10 | gem 'sqlite3', '< 1.4.0', :platform => [:ruby, :mswin, :mingw] 11 | 12 | gem 'rspec-core', '~> 3.8.0' 13 | gem 'rspec-expectations', '~> 3.8.0' 14 | gem 'rspec-mocks', '~> 3.8.0' 15 | gem 'rspec-rails', '~> 3.8.0' 16 | gem 'rspec-support', '~> 3.8.0' 17 | 18 | gem 'rake' 19 | 20 | gem 'sidekiq', '>= 6.4.0' 21 | 22 | platforms :rbx do 23 | gem 'minitest' 24 | gem 'racc' 25 | gem 'rubinius-developer_tools' 26 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 27 | end 28 | 29 | gem 'sucker_punch', '~> 2.0' 30 | 31 | # We need last sinatra that uses rack 2.x and ruby 2.5.x 32 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag =>'v2.1.0' 33 | 34 | gem 'concurrent-ruby', '1.3.4' 35 | gem 'database_cleaner' 36 | gem 'delayed_job', :require => false 37 | gem 'generator_spec' 38 | gem 'redis', '<= 4.8.0' 39 | gem 'resque' 40 | gem 'secure_headers', '~> 6.3.2', :require => false 41 | gem 'simplecov', '<= 0.17.1' 42 | 43 | unless is_jruby 44 | # JRuby doesn't support fork, which is required for this test helper. 45 | gem 'rspec-command' 46 | end 47 | 48 | gem 'mime-types' 49 | 50 | gem 'webmock', :require => false 51 | 52 | gem 'aws-sdk-sqs' 53 | gem 'shoryuken' 54 | 55 | gem 'capistrano', :require => false 56 | 57 | gemspec :path => '../' 58 | -------------------------------------------------------------------------------- /gemfiles/rails60.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'rails', '~> 6.0.2' 10 | gem 'sqlite3', '~> 1.4', :platform => [:ruby, :mswin, :mingw] 11 | 12 | gem 'rspec-rails', '~> 4.0.2' 13 | 14 | gem 'rake' 15 | 16 | gem 'sidekiq', '>= 6.4.0' 17 | 18 | platforms :rbx do 19 | gem 'minitest' 20 | gem 'racc' 21 | gem 'rubinius-developer_tools' 22 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 23 | end 24 | 25 | gem 'sucker_punch', '~> 2.0' 26 | 27 | # We need last sinatra that uses rack 2.x and ruby 2.5.x 28 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag =>'v2.1.0' 29 | 30 | gem 'concurrent-ruby', '1.3.4' 31 | gem 'database_cleaner' 32 | gem 'delayed_job', '4.1.9', :require => false 33 | gem 'generator_spec' 34 | gem 'redis', '<= 4.8.0' 35 | gem 'resque' 36 | gem 'secure_headers', '~> 6.3.2', :require => false 37 | gem 'simplecov' 38 | 39 | unless is_jruby 40 | # JRuby doesn't support fork, which is required for this test helper. 41 | gem 'rspec-command' 42 | end 43 | 44 | gem 'mime-types' 45 | 46 | gem 'webmock', :require => false 47 | 48 | gem 'aws-sdk-sqs' 49 | gem 'shoryuken' 50 | 51 | gem 'capistrano', :require => false 52 | 53 | gemspec :path => '../' 54 | -------------------------------------------------------------------------------- /gemfiles/rails61.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'rails', '~> 6.1.5' 10 | gem 'sqlite3', '~> 1.4', :platform => [:ruby, :mswin, :mingw] 11 | 12 | gem 'rspec-rails', '~> 4.0.2' 13 | 14 | gem 'rake' 15 | 16 | gem 'sidekiq', '>= 6.4.0' 17 | 18 | platforms :rbx do 19 | gem 'minitest' 20 | gem 'racc' 21 | gem 'rubinius-developer_tools' 22 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 23 | end 24 | 25 | gem 'sucker_punch', '~> 2.0' 26 | 27 | # We need last sinatra that uses rack 2.x and ruby 2.5.x 28 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag =>'v2.1.0' 29 | 30 | gem 'concurrent-ruby', '1.3.4' 31 | gem 'database_cleaner' 32 | gem 'delayed_job', '4.1.9', :require => false 33 | gem 'generator_spec' 34 | gem 'redis', '<= 4.8.0' 35 | gem 'resque' 36 | gem 'secure_headers', '~> 6.3.2', :require => false 37 | gem 'simplecov' 38 | 39 | unless is_jruby 40 | # JRuby doesn't support fork, which is required for this test helper. 41 | gem 'rspec-command' 42 | end 43 | 44 | gem 'mime-types' 45 | 46 | gem 'webmock', :require => false 47 | 48 | gem 'aws-sdk-sqs' 49 | gem 'shoryuken' 50 | 51 | gem 'capistrano', :require => false 52 | 53 | gemspec :path => '../' 54 | -------------------------------------------------------------------------------- /gemfiles/rails70.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'rails', '~> 7.0.8' 10 | gem 'sqlite3', '~> 1.4', :platform => [:ruby, :mswin, :mingw] 11 | 12 | gem 'rspec-rails', '~> 6.0.3' 13 | 14 | gem 'rake' 15 | 16 | gem 'sidekiq', '>= 6.4.0' 17 | 18 | platforms :rbx do 19 | gem 'minitest' 20 | gem 'racc' 21 | gem 'rubinius-developer_tools' 22 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 23 | end 24 | 25 | gem 'sucker_punch', '~> 2.0' 26 | 27 | # We need last sinatra that uses rack 2.x and ruby 2.5.x 28 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag =>'v2.1.0' 29 | 30 | gem 'concurrent-ruby', '1.3.4' 31 | gem 'database_cleaner' 32 | gem 'delayed_job', '4.1.10', :require => false 33 | gem 'generator_spec' 34 | gem 'redis', '<= 4.8.0' 35 | gem 'resque' 36 | gem 'secure_headers', '~> 6.3.2', :require => false 37 | gem 'simplecov' 38 | 39 | unless is_jruby 40 | # JRuby doesn't support fork, which is required for this test helper. 41 | gem 'rspec-command' 42 | end 43 | 44 | gem 'mime-types' 45 | 46 | gem 'webmock', :require => false 47 | 48 | gem 'aws-sdk-sqs' 49 | gem 'shoryuken' 50 | 51 | gem 'capistrano', :require => false 52 | 53 | gemspec :path => '../' 54 | -------------------------------------------------------------------------------- /gemfiles/rails71.gemfile: -------------------------------------------------------------------------------- 1 | require 'rubygems/version' 2 | 3 | source 'https://rubygems.org' 4 | 5 | is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 6 | 7 | gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby 8 | gem 'jruby-openssl', :platform => :jruby 9 | gem 'rails', '~> 7.1.0' 10 | gem 'sqlite3', '~> 1.4', :platform => [:ruby, :mswin, :mingw] 11 | 12 | gem 'rspec-rails', '~> 6.0.3' 13 | 14 | gem 'rake' 15 | 16 | gem 'sidekiq', '>= 6.4.0' 17 | 18 | platforms :rbx do 19 | gem 'minitest' 20 | gem 'racc' 21 | gem 'rubinius-developer_tools' 22 | gem 'rubysl', '~> 2.0' if RUBY_VERSION.start_with?('2') 23 | end 24 | 25 | gem 'sucker_punch', '~> 2.0' 26 | 27 | # We need last sinatra that uses rack 2.x and ruby 2.5.x 28 | gem 'sinatra', :git => 'https://github.com/sinatra/sinatra', :tag =>'v2.1.0' 29 | 30 | gem 'database_cleaner' 31 | gem 'delayed_job', '4.1.10', :require => false 32 | gem 'generator_spec' 33 | gem 'redis', '<= 4.8.0' 34 | gem 'resque' 35 | gem 'secure_headers', '~> 6.3.2', :require => false 36 | gem 'simplecov' 37 | 38 | unless is_jruby 39 | # JRuby doesn't support fork, which is required for this test helper. 40 | gem 'rspec-command' 41 | end 42 | 43 | gem 'mime-types' 44 | 45 | gem 'webmock', :require => false 46 | 47 | gem 'aws-sdk-sqs' 48 | gem 'shoryuken' 49 | 50 | gem 'capistrano', :require => false 51 | 52 | gemspec :path => '../' 53 | -------------------------------------------------------------------------------- /lib/generators/rollbar/rollbar_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | require 'rails/generators/named_base' 3 | require 'generators/rollbar/rollbar_generator' 4 | 5 | module Rollbar 6 | module Generators 7 | class RollbarGenerator < ::Rails::Generators::Base 8 | argument :access_token, :type => :string, :banner => 'access_token', 9 | :default => :use_env_sentinel 10 | 11 | source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates')) 12 | 13 | def create_initializer 14 | say 'creating initializer...' 15 | if access_token_configured? 16 | say "It looks like you've already configured Rollbar." 17 | say 'To re-create the config file, remove it first: ' \ 18 | 'config/initializers/rollbar.rb' 19 | exit 20 | end 21 | 22 | begin 23 | require 'ey_config' 24 | rescue LoadError 25 | # Skip loading 26 | end 27 | 28 | if defined? EY::Config 29 | say 'Access token will be read from Engine Yard configuration' 30 | elsif access_token === :use_env_sentinel 31 | say 'Generator run without an access token; assuming you want to ' \ 32 | 'configure using an environment variable.' 33 | say "You'll need to add an environment variable ROLLBAR_ACCESS_TOKEN " \ 34 | 'with your access token:' 35 | say "\n$ export ROLLBAR_ACCESS_TOKEN=yourtokenhere" 36 | say "\nIf that's not what you wanted to do:" 37 | say "\n$ rm config/initializers/rollbar.rb" 38 | say '$ rails generate rollbar yourtokenhere' 39 | say "\n" 40 | else 41 | say 'access token: ' << access_token 42 | end 43 | 44 | template 'initializer.erb', 'config/initializers/rollbar.rb', 45 | :assigns => { :access_token => access_token_expr } 46 | 47 | # TODO: run rake test task 48 | end 49 | 50 | def access_token_expr 51 | if access_token === :use_env_sentinel 52 | "ENV['ROLLBAR_ACCESS_TOKEN']" 53 | else 54 | "'#{access_token}'" 55 | end 56 | end 57 | 58 | def access_token_configured? 59 | File.exist?('config/initializers/rollbar.rb') 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/rails/rollbar_runner.rb: -------------------------------------------------------------------------------- 1 | require 'rails' 2 | require 'rollbar' 3 | 4 | # Rails.root is not present here. 5 | # RSpec needs ENV['DUMMYAPP_PATH'] in order to have a valid path. 6 | # Dir.pwd is used in normal operation. 7 | APP_PATH = File.expand_path( 8 | 'config/application', 9 | (ENV['DUMMYAPP_PATH'] || Dir.pwd) 10 | ) 11 | 12 | module Rails 13 | class RollbarRunner 14 | attr_reader :command 15 | 16 | def initialize 17 | @command = ARGV[0] 18 | end 19 | 20 | def run 21 | prepare_environment 22 | 23 | rollbar_managed { eval_runner } 24 | end 25 | 26 | def prepare_environment 27 | require File.expand_path('../environment', APP_PATH) 28 | ::Rails.application.require_environment! 29 | end 30 | 31 | def eval_runner 32 | if Gem::Version.new(Rails.version) >= Gem::Version.new('5.1.0') 33 | rails5_runner 34 | else 35 | legacy_runner 36 | end 37 | end 38 | 39 | def legacy_runner 40 | string_to_eval = File.read(runner_path) 41 | 42 | ::Rails.module_eval(<<-FILE, __FILE__, __LINE__ + 1) 43 | #{string_to_eval} 44 | FILE 45 | end 46 | 47 | def rails5_runner 48 | require 'rails/command' 49 | 50 | Rails::Command.invoke 'runner', ARGV 51 | end 52 | 53 | def rollbar_managed 54 | yield 55 | rescue StandardError => e 56 | Rollbar.scope(:custom => { :command => command }).error(e) 57 | raise 58 | end 59 | 60 | def runner_path 61 | "#{railties_gem_dir}/lib/rails/commands/runner.rb" 62 | end 63 | 64 | def railties_gem 65 | gem = Gem::Specification.find_by_name('railties') 66 | 67 | abort 'railties gem not found' unless gem 68 | 69 | gem 70 | end 71 | 72 | def railties_gem_dir 73 | railties_gem.gem_dir 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /lib/rollbar/capistrano3.rb: -------------------------------------------------------------------------------- 1 | # This is a tasks file to use with Capistrano 3 2 | 3 | require 'net/http' 4 | require 'rubygems' 5 | require 'json' 6 | require 'rollbar/deploy' 7 | require 'rollbar/capistrano_tasks' 8 | 9 | namespace :rollbar do 10 | # dry_run? wasn't introduced till Capistrano 3.5.0; use the old fetch(:sshkit_backed) 11 | set :dry_run, (proc { 12 | ::Capistrano::Configuration.env.fetch(:sshkit_backend) == 13 | ::SSHKit::Backend::Printer 14 | }) 15 | 16 | desc 'Send deployment started notification to Rollbar.' 17 | task :deploy_started do 18 | on primary fetch(:rollbar_role) do 19 | ::Rollbar::CapistranoTasks.deploy_started(self, self, fetch(:dry_run)) 20 | end 21 | end 22 | 23 | desc 'Send deployment succeeded notification to Rollbar.' 24 | task :deploy_succeeded do 25 | on primary fetch(:rollbar_role) do 26 | ::Rollbar::CapistranoTasks.deploy_succeeded(self, self, fetch(:dry_run)) 27 | end 28 | end 29 | 30 | desc 'Send deployment failed notification to Rollbar.' 31 | task :deploy_failed do 32 | on primary fetch(:rollbar_role) do 33 | ::Rollbar::CapistranoTasks.deploy_failed(self, self, fetch(:dry_run)) 34 | end 35 | end 36 | 37 | task :fail do 38 | raise StandardError 39 | end 40 | end 41 | 42 | namespace :deploy do 43 | after 'deploy:set_current_revision', 'rollbar:deploy_started' 44 | after 'deploy:finished', 'rollbar:deploy_succeeded' 45 | after 'deploy:failed', 'rollbar:deploy_failed' 46 | 47 | # Used for testing :deploy_failed task 48 | # after 'rollbar:deploy_started', 'rollbar:fail' 49 | end 50 | 51 | namespace :load do 52 | task :defaults do 53 | set :rollbar_user, (proc { fetch :local_user, ENV['USER'] || ENV['USERNAME'] }) 54 | set :rollbar_env, (proc { fetch :rails_env, 'production' }) 55 | set :rollbar_token, (proc { 56 | abort 'Please specify the Rollbar access token, ' \ 57 | "set :rollbar_token, 'your token'" 58 | }) 59 | set :rollbar_role, (proc { :app }) 60 | set :rollbar_revision, (proc { fetch :current_revision }) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/rollbar/delay/active_job.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Delay 3 | # This class provides the ActiveJob async handler. Users can 4 | # use ActiveJob in order to send the reports to the Rollbar API 5 | class ActiveJob < ::ActiveJob::Base 6 | queue_as :default 7 | 8 | def perform(payload) 9 | Rollbar.process_from_async_handler(payload) 10 | end 11 | 12 | def self.call(payload) 13 | perform_later payload 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rollbar/delay/delayed_job.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Delay 3 | # This class provides the DelayedJob async handler. Users can 4 | # use DelayedJob in order to send the reports to the Rollbar API 5 | class DelayedJob 6 | class << self 7 | attr_accessor :queue 8 | 9 | def call(payload) 10 | if queue 11 | new.delay(:queue => queue).call(payload) 12 | else 13 | new.delay.call(payload) 14 | end 15 | end 16 | end 17 | 18 | def call(payload) 19 | Rollbar.process_from_async_handler(payload) 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/rollbar/delay/girl_friday.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Delay 3 | class GirlFriday 4 | class << self 5 | def queue_class 6 | ::GirlFriday::WorkQueue 7 | end 8 | 9 | def call(payload) 10 | new.call(payload) 11 | end 12 | 13 | def queue 14 | @queue ||= queue_class.new(nil, :size => 5) do |payload| 15 | Rollbar.process_from_async_handler(payload) 16 | 17 | # Do not rescue. GirlFriday will call the error handler. 18 | end 19 | end 20 | end 21 | 22 | def call(payload) 23 | self.class.queue.push(payload) 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/rollbar/delay/resque.rb: -------------------------------------------------------------------------------- 1 | require 'resque' 2 | 3 | module Rollbar 4 | module Delay 5 | class Resque 6 | def self.call(payload) 7 | new.call(payload) 8 | end 9 | 10 | def call(payload) 11 | ::Resque.enqueue(Job, payload) 12 | end 13 | 14 | class Job 15 | class << self 16 | attr_accessor :queue 17 | end 18 | 19 | self.queue = :default 20 | 21 | def self.perform(payload) 22 | new.perform(payload) 23 | end 24 | 25 | def perform(payload) 26 | Rollbar.process_from_async_handler(payload) 27 | 28 | # Do not rescue. Resque will call the error handler. 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/rollbar/delay/shoryuken.rb: -------------------------------------------------------------------------------- 1 | require 'shoryuken' 2 | 3 | module Rollbar 4 | module Delay 5 | # Following class allows to send rollbars using Sho-ryu-ken as a background 6 | # jobs processor. See the queue_name method which states that your queues 7 | # needs to be names as "rollbar_ENVIRONMENT". Retry intervals will be used 8 | # to retry sending the same message again if failed before. 9 | class Shoryuken 10 | include ::Shoryuken::Worker 11 | 12 | class << self 13 | attr_accessor :queue 14 | end 15 | 16 | self.queue = "rollbar_#{Rollbar.configuration.environment}" 17 | 18 | def self.call(payload) 19 | new.call(payload, :queue => queue) 20 | end 21 | 22 | def call(payload, options = {}) 23 | self.class.perform_async(payload, options) 24 | end 25 | 26 | # not allowing bulk, to not double-report rollbars if one of them failed in bunch. 27 | shoryuken_options :auto_delete => true, 28 | :body_parser => :json, 29 | :retry_intervals => [60, 180, 360, 120_0, 360_0, 186_00] 30 | 31 | def perform(_sqs_message, payload) 32 | Rollbar.process_from_async_handler(payload) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/rollbar/delay/sidekiq.rb: -------------------------------------------------------------------------------- 1 | require 'sidekiq' 2 | 3 | module Rollbar 4 | module Delay 5 | class Sidekiq 6 | OPTIONS = { 'queue' => 'rollbar', 'class' => Rollbar::Delay::Sidekiq }.freeze 7 | 8 | def initialize(*args) 9 | @options = (opts = args.shift) ? OPTIONS.merge(opts) : OPTIONS 10 | end 11 | 12 | def call(payload) 13 | return unless ::Sidekiq::Client.push(@options.merge('args' => [payload])).nil? 14 | 15 | raise(StandardError, 'Unable to push the job to Sidekiq') 16 | end 17 | 18 | include ::Sidekiq::Worker 19 | 20 | def perform(*args) 21 | Rollbar.process_from_async_handler(*args) 22 | 23 | # Do not rescue. Sidekiq will call the error handler. 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/rollbar/delay/sucker_punch.rb: -------------------------------------------------------------------------------- 1 | require 'sucker_punch' 2 | require 'sucker_punch/version' 3 | 4 | module Rollbar 5 | module Delay 6 | class SuckerPunch 7 | include ::SuckerPunch::Job 8 | 9 | class << self 10 | attr_accessor :perform_proc, :ready 11 | end 12 | 13 | self.ready = false 14 | 15 | def self.setup 16 | major_version = ::SuckerPunch::VERSION.split.first.to_i 17 | 18 | self.perform_proc = if major_version > 1 19 | proc { |payload| perform_async(payload) } 20 | else 21 | proc { |payload| new.async.perform(payload) } 22 | end 23 | 24 | self.ready = true 25 | end 26 | 27 | def self.call(payload) 28 | setup unless ready 29 | 30 | perform_proc.call(payload) 31 | end 32 | 33 | def perform(*args) 34 | Rollbar.process_from_async_handler(*args) 35 | 36 | # SuckerPunch can configure an exception handler with: 37 | # 38 | # SuckerPunch.exception_handler { # do something here } 39 | # 40 | # This is just passed to Celluloid.exception_handler which will 41 | # push the reiceved block to an array of handlers, by default empty, []. 42 | # 43 | 44 | # Do not rescue. SuckerPunch will call the error handler. 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /lib/rollbar/delay/thread.rb: -------------------------------------------------------------------------------- 1 | require 'timeout' 2 | 3 | module Rollbar 4 | module Delay 5 | class Thread 6 | EXIT_SIGNAL = :exit 7 | EXIT_TIMEOUT = 6 8 | 9 | Error = Class.new(StandardError) 10 | TimeoutError = Class.new(Error) 11 | 12 | DEFAULT_PRIORITY = 1 13 | 14 | class << self 15 | attr_writer :options 16 | attr_reader :reaper 17 | 18 | def call(payload) 19 | spawn_threads_reaper 20 | 21 | thread = new.call(payload) 22 | threads << thread 23 | thread 24 | end 25 | 26 | def options 27 | @options || {} 28 | end 29 | 30 | private 31 | 32 | def threads 33 | @threads ||= Queue.new 34 | end 35 | 36 | def spawn_threads_reaper 37 | return if @spawned 38 | 39 | @spawned = true 40 | 41 | @reaper ||= build_reaper_thread 42 | configure_exit_handler 43 | end 44 | 45 | def build_reaper_thread 46 | ::Thread.start do 47 | loop do 48 | thread = threads.pop 49 | 50 | break if thread == EXIT_SIGNAL 51 | 52 | thread.join 53 | end 54 | end 55 | end 56 | 57 | def configure_exit_handler 58 | at_exit do 59 | begin 60 | Timeout.timeout(EXIT_TIMEOUT) do 61 | threads << EXIT_SIGNAL 62 | reaper.join 63 | end 64 | rescue Timeout::Error 65 | raise TimeoutError, 66 | "unable to reap all threads within #{EXIT_TIMEOUT} seconds" 67 | end 68 | end 69 | end 70 | end 71 | 72 | def priority 73 | self.class.options[:priority] || DEFAULT_PRIORITY 74 | end 75 | 76 | def call(payload) 77 | priority = self.priority 78 | 79 | ::Thread.new do 80 | begin 81 | ::Thread.current.priority = priority 82 | Rollbar.process_from_async_handler(payload) 83 | rescue StandardError 84 | # Here we swallow the exception: 85 | # 1. The original report wasn't sent. 86 | # 2. An internal error was sent and logged 87 | # 88 | # If users want to handle this in some way they 89 | # can provide a more custom Thread based implementation 90 | end 91 | end 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /lib/rollbar/deploy.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | module Rollbar 4 | # Deploy Tracking API wrapper module 5 | module Deploy 6 | ENDPOINT = 'https://api.rollbar.com/api/1/deploy/'.freeze 7 | 8 | def self.report(opts, access_token, environment, revision) 9 | return {} unless access_token && !access_token.empty? 10 | 11 | opts[:status] ||= :started 12 | 13 | uri = ::URI.parse(::Rollbar::Deploy::ENDPOINT) 14 | 15 | request_data = { 16 | :access_token => access_token, 17 | :environment => environment, 18 | :revision => revision 19 | }.merge(opts) 20 | request_data.delete(:proxy) 21 | request_data.delete(:dry_run) 22 | 23 | request = ::Net::HTTP::Post.new(uri.request_uri) 24 | request.body = ::JSON.dump(request_data) 25 | 26 | send_request(opts, uri, request) 27 | end 28 | 29 | def self.update(opts, access_token, deploy_id, status) 30 | return {} unless access_token && !access_token.empty? 31 | 32 | uri = ::URI.parse( 33 | "#{::Rollbar::Deploy::ENDPOINT}#{deploy_id}?access_token=#{access_token}" 34 | ) 35 | 36 | request = ::Net::HTTP::Patch.new(uri.request_uri) 37 | request.body = ::JSON.dump(:status => status.to_s, :comment => opts[:comment]) 38 | 39 | send_request(opts, uri, request) 40 | end 41 | 42 | class << self 43 | private 44 | 45 | def send_request(opts, uri, request) 46 | ::Net::HTTP.start(uri.host, uri.port, opts[:proxy], :use_ssl => true) do |http| 47 | build_result( 48 | uri, 49 | request, 50 | opts[:dry_run] ? nil : http.request(request), 51 | opts[:dry_run] 52 | ) 53 | end 54 | end 55 | 56 | def build_result(uri, request, response = nil, dry_run = false) 57 | result = {} 58 | result.merge!(request_result(uri, request)) 59 | result.merge!(response_result(response)) unless response.nil? 60 | result[:success] = success?(result, dry_run) 61 | result 62 | end 63 | 64 | def success?(result, dry_run = false) 65 | return true if dry_run 66 | 67 | result[:response] && 68 | result[:response].is_a?(::Net::HTTPSuccess) && 69 | result[:response].code == '200' && 70 | (result.key?('err') ? result['err'].to_i.zero? : true) 71 | end 72 | 73 | def request_result(uri, request) 74 | { 75 | :request_info => "#{uri.inspect}: #{request.body}", 76 | :request => request 77 | } 78 | end 79 | 80 | def response_result(response) 81 | code = response.code 82 | message = response.message 83 | body = response.body.delete("\n") 84 | { 85 | :response => response, 86 | :response_info => "#{code}; #{message}; #{body}" 87 | }.merge(::JSON.parse(response.body, :symbolize_names => true)) 88 | end 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/rollbar/encoding.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Encoding 3 | class << self 4 | attr_accessor :encoding_class 5 | end 6 | 7 | def self.setup 8 | require 'rollbar/encoding/encoder' 9 | self.encoding_class = Rollbar::Encoding::Encoder 10 | end 11 | 12 | def self.encode(object) 13 | can_be_encoded = object.is_a?(String) || object.is_a?(Symbol) 14 | 15 | return object unless can_be_encoded 16 | 17 | encoding_class.new(object).encode 18 | end 19 | end 20 | end 21 | 22 | Rollbar::Encoding.setup 23 | -------------------------------------------------------------------------------- /lib/rollbar/encoding/encoder.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Encoding 3 | class Encoder 4 | ALL_ENCODINGS = [::Encoding::UTF_8, ::Encoding::ISO_8859_1, ::Encoding::ASCII_8BIT, 5 | ::Encoding::US_ASCII].freeze 6 | ASCII_ENCODINGS = [::Encoding::US_ASCII, ::Encoding::ASCII_8BIT, 7 | ::Encoding::ISO_8859_1].freeze 8 | UTF8 = 'UTF-8'.freeze 9 | BINARY = 'binary'.freeze 10 | 11 | attr_accessor :object 12 | 13 | def initialize(object) 14 | @object = object 15 | end 16 | 17 | def encode 18 | value = object.to_s 19 | encoding = value.encoding 20 | 21 | # This will be most of cases so avoid force anything for them 22 | encoded_value = if encoding == ::Encoding::UTF_8 && value.valid_encoding? 23 | value 24 | else 25 | force_encoding(value).encode( 26 | *encoding_args(value), 27 | # Ruby 2.7 requires this to look like keyword args, 28 | # and Ruby 1.9.3 doesn't understand keyword args, so 29 | # don't use hash rockets here and both will be happy. 30 | invalid: :replace, undef: :replace, replace: '' # rubocop:disable Style/HashSyntax 31 | ) 32 | end 33 | 34 | object.is_a?(Symbol) ? encoded_value.to_sym : encoded_value 35 | rescue StandardError => e 36 | # If encoding fails for any reason, replace the string with a diagnostic error. 37 | "error encoding string: #{e.class}: #{e.message}" 38 | end 39 | 40 | private 41 | 42 | def force_encoding(value) 43 | return value if value.frozen? 44 | 45 | if value.encoding == ::Encoding::UTF_8 46 | value.force_encoding(detect_encoding(value)) 47 | end 48 | 49 | value 50 | end 51 | 52 | def detect_encoding(v) 53 | value = v.dup 54 | 55 | ALL_ENCODINGS.detect do |encoding| 56 | begin 57 | # Seems #codepoints is faster than #valid_encoding? 58 | value.force_encoding(encoding).encode(::Encoding::UTF_8).codepoints 59 | true 60 | rescue StandardError 61 | false 62 | end 63 | end 64 | end 65 | 66 | def encoding_args(value) 67 | args = [UTF8] 68 | args << BINARY if ASCII_ENCODINGS.include?(value.encoding) 69 | 70 | args 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/rollbar/exception_reporter.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module ExceptionReporter # :nodoc: 3 | def report_exception_to_rollbar(env, exception) 4 | return unless capture_uncaught? 5 | 6 | log_exception_message(exception) 7 | 8 | exception_data = exception_data(exception) 9 | 10 | case exception_data 11 | when Hash 12 | env['rollbar.exception_uuid'] = exception_data[:uuid] 13 | Rollbar.log_debug( 14 | "[Rollbar] Exception uuid saved in env: #{exception_data[:uuid]}" 15 | ) 16 | when 'disabled' 17 | Rollbar.log_debug( 18 | '[Rollbar] Exception not reported because Rollbar is disabled' 19 | ) 20 | when 'ignored' 21 | Rollbar.log_debug '[Rollbar] Exception not reported because it was ignored' 22 | end 23 | rescue StandardError => e 24 | Rollbar.log_warning( 25 | "[Rollbar] Exception while reporting exception to Rollbar: #{e.message}" 26 | ) 27 | end 28 | 29 | def capture_uncaught? 30 | Rollbar.configuration.capture_uncaught != false && 31 | !Rollbar.configuration.enable_rails_error_subscriber 32 | end 33 | 34 | def log_exception_message(exception) 35 | exception_message = exception.message if exception.respond_to?(:message) 36 | exception_message ||= 'No Exception Message' 37 | Rollbar.log_debug "[Rollbar] Reporting exception: #{exception_message}" 38 | end 39 | 40 | def exception_data(exception) 41 | Rollbar.log(Rollbar.configuration.uncaught_exception_level, exception, 42 | :use_exception_level_filters => true) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/rollbar/exceptions.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | class Ignore < StandardError; end 3 | end 4 | -------------------------------------------------------------------------------- /lib/rollbar/js.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Js 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/rollbar/json.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/language_support' 2 | require 'json' 3 | 4 | module Rollbar 5 | module JSON # :nodoc: 6 | module_function 7 | 8 | def dump(object) 9 | Rollbar.plugins.get('basic_socket').load_scoped!(true) do 10 | ::JSON.generate(object) 11 | end 12 | end 13 | 14 | def load(string) 15 | ::JSON.parse(string) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/rollbar/language_support.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module LanguageSupport 3 | module_function 4 | 5 | def const_defined?(mod, target, inherit = true) 6 | mod.const_defined?(target, inherit) 7 | end 8 | 9 | def const_get(mod, target, inherit = true) 10 | mod.const_get(target, inherit) 11 | end 12 | 13 | def version?(version) 14 | numbers = version.split('.') 15 | 16 | numbers == ::RUBY_VERSION.split('.')[0, numbers.size] 17 | end 18 | 19 | def timeout_exceptions 20 | [Net::ReadTimeout, Net::OpenTimeout] 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/rollbar/lazy_store.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | class LazyStore 3 | attr_reader :loaded_data, :raw 4 | private :loaded_data 5 | 6 | def initialize(initial_data) 7 | initial_data ||= {} 8 | 9 | @raw = initial_data 10 | @loaded_data = {} 11 | end 12 | 13 | def eql?(other) 14 | if other.is_a?(self.class) 15 | raw.eql?(other.raw) 16 | else 17 | raw.eql?(other) 18 | end 19 | end 20 | 21 | def ==(other) 22 | raw == if other.is_a?(self.class) 23 | other.raw 24 | else 25 | other 26 | end 27 | end 28 | 29 | # With this version of clone we ensure that the loaded_data is empty 30 | def clone 31 | self.class.new(raw.clone) 32 | end 33 | 34 | def [](key) 35 | load_value(key) 36 | end 37 | 38 | def []=(key, value) 39 | raw[key] = value 40 | 41 | loaded_data.delete(key) 42 | end 43 | 44 | def data 45 | raw.reduce({}) do |acc, (k, _)| 46 | acc[k] = self[k] 47 | 48 | acc 49 | end 50 | end 51 | 52 | private 53 | 54 | def load_value(key) 55 | return loaded_data[key] if loaded_data.key?(key) 56 | return unless raw.key?(key) 57 | 58 | value = find_value(key) 59 | loaded_data[key] = value 60 | 61 | value 62 | end 63 | 64 | def find_value(key) 65 | value = raw[key] 66 | value.respond_to?(:call) ? value.call : value 67 | end 68 | 69 | def method_missing(method_sym, *args, &block) 70 | return raw.send(method_sym, *args, &block) if raw.respond_to?(method_sym) 71 | 72 | super 73 | end 74 | 75 | def respond_to_missing?(method_sym, include_all) 76 | raw.respond_to?(method_sym, include_all) 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/rollbar/logger.rb: -------------------------------------------------------------------------------- 1 | require 'logger' 2 | require 'rollbar' 3 | 4 | module Rollbar 5 | # This class provides logger interface that can be used to replace 6 | # the application logger and send all the log messages to Rollbar 7 | # 8 | # Usage: 9 | # require 'rollbar/logger' 10 | # logger = Rollbar::Logger.new 11 | # logger.error('Error processing purchase') 12 | # 13 | # If using Rails, you can extend the Rails logger so messages are logged 14 | # normally and also to Rollbar: 15 | # 16 | # Rails.logger.extend(ActiveSupport::Logger.broadcast(Rollbar::Logger.new)) 17 | class Logger < ::Logger 18 | class Error < RuntimeError; end 19 | 20 | def initialize 21 | super(nil) 22 | 23 | self.level = ERROR 24 | end 25 | 26 | def add(severity, message = nil, progname = nil) 27 | return true if severity < @level 28 | 29 | message ||= block_given? ? yield : progname 30 | 31 | return true if blank?(message) 32 | 33 | rollbar.log(rollbar_level(severity), message) 34 | end 35 | 36 | def <<(message) 37 | error(message) 38 | end 39 | 40 | # Returns a Rollbar::Notifier instance with the current global scope and 41 | # with a logger writing to /dev/null so we don't have a infinite loop 42 | # when Rollbar.configuration.logger is Rails.logger. 43 | def rollbar 44 | notifier = Rollbar.scope 45 | notifier.configuration.logger = ::Logger.new('/dev/null') 46 | 47 | notifier 48 | end 49 | 50 | private 51 | 52 | def blank?(message) 53 | return message.blank? if message.respond_to?(:blank?) 54 | 55 | message.respond_to?(:empty?) ? !!message.empty? : !message 56 | end 57 | 58 | # Find correct Rollbar level to use using the indexes in Logger::Severity 59 | # DEBUG = 0 60 | # INFO = 1 61 | # WARN = 2 62 | # ERROR = 3 63 | # FATAL = 4 64 | # UNKNOWN = 5 65 | # 66 | # If not found we'll use 'error' as the used level 67 | def rollbar_level(severity) 68 | [:debug, :info, :warning, :error, :critical, :error][severity] || :error 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/rollbar/logger_proxy.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | class LoggerProxy 3 | attr_reader :object 4 | 5 | def initialize(object) 6 | @object = object 7 | end 8 | 9 | def debug(message) 10 | log('debug', message) 11 | end 12 | 13 | def info(message) 14 | log('info', message) 15 | end 16 | 17 | def warn(message) 18 | log('warn', message) 19 | end 20 | 21 | def error(message) 22 | log('error', message) 23 | end 24 | 25 | def log(level, message) 26 | unless Rollbar.configuration.enabled && acceptable_levels.include?(level.to_sym) 27 | return 28 | end 29 | 30 | @object.send(level, message) 31 | rescue StandardError 32 | puts "[Rollbar] Error logging #{level}:" 33 | puts "[Rollbar] #{message}" 34 | end 35 | 36 | protected 37 | 38 | def acceptable_levels 39 | @acceptable_levels ||= begin 40 | levels = [:debug, :info, :warn, :error] 41 | if Rollbar.configuration.logger_level 42 | levels[levels.find_index(Rollbar.configuration.logger_level)..-1] 43 | else 44 | [] 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/js/json_value.rb: -------------------------------------------------------------------------------- 1 | # Allows a Ruby String to be used to pass native Javascript objects/functions 2 | # when calling JSON#generate with a Rollbar::JSON::JsOptionsState instance. 3 | # 4 | # Example: 5 | # JSON.generate( 6 | # { foo: Rollbar::JSON::Value.new('function(){ alert("bar") }') }, 7 | # Rollbar::JSON::JsOptionsState.new 8 | # ) 9 | # 10 | # => '{"foo":function(){ alert(\"bar\") }}' 11 | # 12 | # MUST use the Ruby JSON encoder, as in the example. The ActiveSupport encoder, 13 | # which is installed with Rails, is invoked when calling Hash#to_json and #as_json, 14 | # and will not work. 15 | # 16 | module Rollbar 17 | module JSON 18 | class JsOptionsState < ::JSON::State; end 19 | 20 | class Value # :nodoc: 21 | attr_accessor :value 22 | 23 | def initialize(value) 24 | @value = value 25 | end 26 | 27 | def to_json(opts = {}) 28 | # Return the raw value if this is from the js middleware 29 | return value if opts.class == Rollbar::JSON::JsOptionsState 30 | 31 | # Otherwise convert to a string 32 | %Q["#{value}"] 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/rack.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar' 2 | require 'rollbar/exception_reporter' 3 | require 'rollbar/request_data_extractor' 4 | 5 | module Rollbar 6 | module Middleware 7 | class Rack 8 | include ::Rollbar::ExceptionReporter 9 | include RequestDataExtractor 10 | 11 | def initialize(app) 12 | @app = app 13 | end 14 | 15 | def call(env) 16 | Rollbar.reset_notifier! 17 | 18 | Rollbar.scoped(fetch_scope(env)) do 19 | begin 20 | Rollbar.notifier.enable_locals 21 | response = @app.call(env) 22 | report_exception_to_rollbar(env, framework_error(env)) if framework_error(env) 23 | response 24 | rescue Exception => e # rubocop:disable Lint/RescueException 25 | report_exception_to_rollbar(env, e) 26 | raise 27 | ensure 28 | Rollbar.notifier.disable_locals 29 | end 30 | end 31 | end 32 | 33 | def fetch_scope(env) 34 | { 35 | :request => proc { extract_request_data_from_rack(env) }, 36 | :person => person_data_proc(env) 37 | } 38 | rescue Exception => e # rubocop:disable Lint/RescueException 39 | report_exception_to_rollbar(env, e) 40 | raise 41 | end 42 | 43 | def person_data_proc(env) 44 | proc { extract_person_data_from_controller(env) } 45 | end 46 | 47 | def framework_error(env) 48 | env['rack.exception'] 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/rack/builder.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/exception_reporter' 2 | require 'rollbar/request_data_extractor' 3 | 4 | module Rollbar 5 | module Middleware 6 | class Rack 7 | module Builder 8 | include ExceptionReporter 9 | include RequestDataExtractor 10 | 11 | def call_with_rollbar(env) 12 | Rollbar.reset_notifier! 13 | 14 | Rollbar.scoped(fetch_scope(env)) do 15 | begin 16 | call_without_rollbar(env) 17 | rescue ::Exception => e # rubocop:disable Lint/RescueException 18 | report_exception_to_rollbar(env, e) 19 | raise 20 | end 21 | end 22 | end 23 | 24 | def fetch_scope(env) 25 | { 26 | :request => proc { extract_request_data_from_rack(env) }, 27 | :person => person_data_proc(env) 28 | } 29 | rescue Exception => e # rubocop:disable Lint/RescueException 30 | report_exception_to_rollbar(env, e) 31 | raise 32 | end 33 | 34 | def person_data_proc(env) 35 | proc { extract_person_data_from_controller(env) } 36 | end 37 | 38 | def self.included(base) 39 | base.send(:alias_method, :call_without_rollbar, :call) 40 | base.send(:alias_method, :call, :call_with_rollbar) 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/rack/test_session.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Middleware 3 | class Rack 4 | module TestSession 5 | include ExceptionReporter 6 | 7 | def env_for_with_rollbar(path, env) 8 | env_for_without_rollbar(path, env) 9 | rescue Exception => e # rubocop:disable Lint/RescueException 10 | report_exception_to_rollbar(env, e) 11 | raise e 12 | end 13 | 14 | def self.included(base) 15 | base.send(:alias_method, :env_for_without_rollbar, :env_for) 16 | base.send(:alias_method, :env_for, :env_for_with_rollbar) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/rails/rollbar.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/request_data_extractor' 2 | require 'rollbar/exception_reporter' 3 | 4 | module Rollbar 5 | module Middleware 6 | module Rails 7 | class RollbarMiddleware 8 | include RequestDataExtractor 9 | include ExceptionReporter 10 | 11 | def initialize(app) 12 | @app = app 13 | end 14 | 15 | def call(env) 16 | self.request_data = nil 17 | 18 | Rollbar.reset_notifier! 19 | 20 | env['rollbar.scope'] = scope = fetch_scope(env) 21 | 22 | Rollbar.scoped(scope) do 23 | begin 24 | Rollbar.notifier.enable_locals 25 | response = @app.call(env) 26 | 27 | if (framework_exception = env['action_dispatch.exception']) 28 | report_exception_to_rollbar(env, framework_exception) 29 | end 30 | 31 | response 32 | rescue Exception => e # rubocop:disable Lint/RescueException 33 | report_exception_to_rollbar(env, e) 34 | raise 35 | ensure 36 | Rollbar.notifier.disable_locals 37 | end 38 | end 39 | end 40 | 41 | def fetch_scope(env) 42 | # Scope a new notifier with request data and a Proc for person data 43 | # for any reports that happen while a controller is handling a request 44 | 45 | { 46 | :request => proc { request_data(env) }, 47 | :person => person_data_proc(env), 48 | :context => proc { context(request_data(env)) } 49 | } 50 | end 51 | 52 | def request_data(env) 53 | Thread.current[:'_rollbar.rails.request_data'] ||= extract_request_data(env) 54 | end 55 | 56 | def request_data=(value) 57 | Thread.current[:'_rollbar.rails.request_data'] = value 58 | end 59 | 60 | def extract_request_data(env) 61 | extract_request_data_from_rack(env) 62 | end 63 | 64 | def person_data_proc(env) 65 | block = proc { extract_person_data_from_controller(env) } 66 | unless defined?(ActiveRecord::Base) && ActiveRecord::Base.connected? 67 | return block 68 | end 69 | 70 | proc do 71 | begin 72 | ActiveRecord::Base.connection_pool.with_connection(&block) 73 | rescue ActiveRecord::ConnectionTimeoutError 74 | {} 75 | end 76 | end 77 | end 78 | 79 | def context(request_data) 80 | route_params = request_data[:params] 81 | 82 | # make sure route is a hash built by RequestDataExtractor 83 | return unless route_params.is_a?(Hash) && !route_params.empty? 84 | 85 | "#{route_params[:controller]}##{route_params[:action]}" 86 | end 87 | end 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/rails/show_exceptions.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Middleware 3 | module Rails 4 | module ShowExceptions 5 | include ExceptionReporter 6 | 7 | def render_exception_with_rollbar(env, exception, wrapper = nil) 8 | key = 'action_dispatch.show_detailed_exceptions' 9 | 10 | if exception.is_a?(ActionController::RoutingError) && env.params[key.to_s] 11 | scope = extract_scope_from(env) 12 | 13 | Rollbar.scoped(scope) do 14 | report_exception_to_rollbar(env, exception) 15 | end 16 | end 17 | 18 | # Rails 7.1 changes the method signature for render_exception. 19 | if self.class.instance_method(:render_exception_without_rollbar).arity == 2 20 | render_exception_without_rollbar(env, exception) 21 | else 22 | render_exception_without_rollbar(env, exception, wrapper) 23 | end 24 | end 25 | 26 | def call_with_rollbar(env) 27 | call_without_rollbar(env) 28 | rescue ActionController::RoutingError => e 29 | # won't reach here if show_detailed_exceptions is true 30 | scope = extract_scope_from(env) 31 | 32 | Rollbar.scoped(scope) do 33 | report_exception_to_rollbar(env, e) 34 | end 35 | 36 | raise e 37 | end 38 | 39 | def extract_scope_from(env) 40 | scope = env['rollbar.scope'] 41 | unless scope 42 | Rollbar.log_warn( 43 | '[Rollbar] rollbar.scope key has been removed from Rack env.' 44 | ) 45 | end 46 | 47 | scope || {} 48 | end 49 | 50 | def self.included(base) 51 | base.send(:alias_method, :call_without_rollbar, :call) 52 | base.send(:alias_method, :call, :call_with_rollbar) 53 | 54 | base.send(:alias_method, :render_exception_without_rollbar, :render_exception) 55 | base.send(:alias_method, :render_exception, :render_exception_with_rollbar) 56 | end 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/rollbar/middleware/sinatra.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/middleware/rack' 2 | 3 | module Rollbar 4 | module Middleware 5 | class Sinatra < Rollbar::Middleware::Rack 6 | def framework_error(env) 7 | env['sinatra.error'] 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/rollbar/notifier/trace_with_bindings.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | class Notifier 3 | class TraceWithBindings # :nodoc: 4 | attr_reader :frames, :exception_frames 5 | 6 | def initialize 7 | reset 8 | end 9 | 10 | def reset 11 | @frames = [] 12 | @exception_frames = [] 13 | @exception_signature = nil 14 | end 15 | 16 | def enable 17 | reset 18 | trace_point.enable if defined?(TracePoint) 19 | end 20 | 21 | def disable 22 | trace_point.disable if defined?(TracePoint) 23 | end 24 | 25 | private 26 | 27 | def exception_signature(trace) 28 | # use the exception backtrace to detect reraised exception. 29 | trace.raised_exception.backtrace.first 30 | end 31 | 32 | def detect_reraise(trace) 33 | @exception_signature == exception_signature(trace) 34 | end 35 | 36 | def trace_point 37 | return unless defined?(TracePoint) 38 | 39 | @trace_point ||= TracePoint.new(:call, :return, :b_call, :b_return, :c_call, 40 | :c_return, :raise) do |tp| 41 | case tp.event 42 | when :call, :b_call, :c_call, :class 43 | frames.push frame(tp) 44 | when :return, :b_return, :c_return, :end 45 | frames.pop 46 | when :raise 47 | unless detect_reraise(tp) # ignore reraised exceptions 48 | # may be possible to optimize better than #dup 49 | @exception_frames = @frames.dup 50 | @exception_signature = exception_signature(tp) 51 | end 52 | end 53 | end 54 | end 55 | 56 | def frame(trace) 57 | { 58 | :binding => binding(trace), 59 | :defined_class => trace.defined_class, 60 | :method_id => trace.method_id, 61 | :path => trace.path, 62 | :lineno => trace.lineno 63 | } 64 | end 65 | 66 | def binding(trace) 67 | trace.binding 68 | rescue StandardError 69 | # Ruby internals will raise if we're on a Fiber, 70 | # since bindings aren't valid on Fibers. 71 | nil 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/rollbar/plugins.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/plugin' 2 | 3 | module Rollbar 4 | # Stores the available plugin definitions and loads them 5 | class Plugins 6 | attr_reader :collection 7 | 8 | def initialize 9 | @collection = [] 10 | end 11 | 12 | def require_all 13 | Dir.glob(plugin_files).each do |file| 14 | require file.to_s 15 | end 16 | end 17 | 18 | def plugin_files 19 | File.expand_path('../plugins/*.rb', __FILE__) 20 | end 21 | 22 | def define(name, &block) 23 | return if loaded?(name) 24 | 25 | plugin = Rollbar::Plugin.new(name) 26 | collection << plugin 27 | 28 | plugin.instance_eval(&block) 29 | end 30 | 31 | def load! 32 | collection.each do |plugin| 33 | plugin.load! unless plugin.on_demand 34 | end 35 | end 36 | 37 | def get(name) 38 | collection.find { |plugin| plugin.name == name } 39 | end 40 | 41 | private 42 | 43 | def loaded?(name) 44 | collection.any? { |plugin| plugin.name == name } 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/active_job.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | # Report any uncaught errors in a job to Rollbar and reraise 3 | module ActiveJob 4 | def self.included(base) 5 | base.send :rescue_from, Exception do |exception| 6 | job_data = { 7 | :job => self.class.name, 8 | :use_exception_level_filters => true 9 | } 10 | 11 | # When included in ActionMailer, the handler is called twice. 12 | # This detects the execution that has the expected state. 13 | if defined?(ActionMailer::Base) && self.class.ancestors.include?(ActionMailer::Base) 14 | job_data[:action] = action_name 15 | job_data[:params] = @params 16 | 17 | Rollbar.error(exception, job_data) 18 | 19 | # This detects other supported integrations. 20 | elsif defined?(arguments) 21 | job_data[:arguments] = \ 22 | if self.class.respond_to?(:log_arguments?) && !self.class.log_arguments? 23 | arguments.map(&Rollbar::Scrubbers.method(:scrub_value)) 24 | else 25 | arguments 26 | end 27 | job_data[:job_id] = job_id if defined?(job_id) 28 | 29 | Rollbar.error(exception, job_data) 30 | end 31 | 32 | raise exception 33 | end 34 | end 35 | end 36 | end 37 | 38 | Rollbar.plugins.define('active_job') do 39 | dependency { !configuration.disable_monkey_patch } 40 | dependency { !configuration.disable_action_mailer_monkey_patch } 41 | 42 | execute do 43 | if defined?(ActiveSupport) && ActiveSupport.respond_to?(:on_load) 44 | ActiveSupport.on_load(:action_mailer) do 45 | if defined?(ActionMailer::MailDeliveryJob) # Rails >= 6.0 46 | ActionMailer::Base.send(:include, Rollbar::ActiveJob) 47 | elsif defined?(ActionMailer::DeliveryJob) # Rails < 6.0 48 | ActionMailer::DeliveryJob.send(:include, 49 | Rollbar::ActiveJob) 50 | end 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/basic_socket.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('basic_socket') do 2 | load_on_demand 3 | 4 | dependency { !configuration.disable_core_monkey_patch } 5 | 6 | # Needed to avoid active_support (< 4.1.0) bug serializing JSONs 7 | dependency do 8 | defined?(ActiveSupport::VERSION::STRING) && 9 | Gem::Version.new(ActiveSupport::VERSION::STRING) < Gem::Version.new('4.1.0') 10 | end 11 | 12 | execute do 13 | class BasicSocket # :nodoc: 14 | def new_as_json(_options = nil) 15 | { 16 | :value => inspect 17 | } 18 | end 19 | # alias_method is recommended over alias when aliasing at runtime. 20 | # https://github.com/rubocop-hq/ruby-style-guide#alias-method 21 | alias_method :original_as_json, :as_json # rubocop:disable Style/Alias 22 | alias_method :as_json, :new_as_json # rubocop:disable Style/Alias 23 | end 24 | end 25 | 26 | revert do 27 | class BasicSocket # :nodoc: 28 | alias_method :as_json, :original_as_json # rubocop:disable Style/Alias 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/delayed_job.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('delayed_job') do 2 | dependency { !configuration.disable_monkey_patch } 3 | dependency do 4 | defined?(Delayed) && defined?(Delayed::Worker) && configuration.delayed_job_enabled 5 | end 6 | 7 | execute do 8 | require 'rollbar/plugins/delayed_job/plugin' 9 | 10 | Rollbar::Delayed.wrap_worker 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/delayed_job/job_data.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Delayed 3 | class JobData 4 | attr_reader :job 5 | 6 | def initialize(job) 7 | @job = job 8 | end 9 | 10 | def to_hash 11 | job_data = extract_job_data 12 | 13 | handler_parent = job_data['job'] || job_data 14 | handler_parent['handler'] = handler_data 15 | 16 | job_data 17 | end 18 | 19 | private 20 | 21 | def extract_job_data 22 | if job.respond_to?(:as_json) 23 | job.as_json 24 | else 25 | Hash[job.to_hash.map { |k, v| [k.to_s, v] }] 26 | end 27 | end 28 | 29 | def handler_data 30 | payload_object = job.payload_object 31 | 32 | return payload_object unless payload_object.respond_to?(:object) 33 | 34 | object_data(payload_object.object) 35 | rescue StandardError 36 | {} 37 | end 38 | 39 | def object_data(object) 40 | { 41 | :method_name => job.payload_object.method_name, 42 | :args => job.payload_object.args, 43 | :object => object.is_a?(Class) ? object.name : object.to_s 44 | } 45 | rescue StandardError 46 | {} 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/delayed_job/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'delayed_job' 2 | require 'rollbar/plugins/delayed_job/job_data' 3 | 4 | module Rollbar 5 | module Delayed 6 | class << self 7 | attr_accessor :wrapped 8 | end 9 | 10 | class RollbarPlugin < ::Delayed::Plugin 11 | callbacks do |lifecycle| 12 | lifecycle.around(:invoke_job, &Delayed.invoke_job_callback) 13 | lifecycle.after(:failure) do |_, job, _, _| 14 | data = Rollbar::Delayed.build_job_data(job) 15 | 16 | # DelayedJob < 4.1 doesn't provide job#error 17 | if job.class.method_defined? :error 18 | if job.error 19 | ::Rollbar.scope(:request => data) 20 | .error(job.error, :use_exception_level_filters => true) 21 | end 22 | elsif job.last_error 23 | ::Rollbar.scope(:request => data).error( 24 | "Job has failed and won't be retried anymore: #{job.last_error}", 25 | :use_exception_level_filters => true 26 | ) 27 | end 28 | end 29 | end 30 | end 31 | 32 | self.wrapped = false 33 | 34 | def self.wrap_worker 35 | return if wrapped 36 | 37 | ::Delayed::Worker.plugins << RollbarPlugin 38 | 39 | self.wrapped = true 40 | end 41 | 42 | def self.wrap_worker! 43 | self.wrapped = false 44 | 45 | wrap_worker 46 | end 47 | 48 | def self.invoke_job_callback 49 | proc do |job, *args, &block| 50 | begin 51 | if Rollbar.configuration.dj_use_scoped_block 52 | data = Rollbar::Delayed.build_job_data(job) 53 | Rollbar.scoped(:request => data) { block.call(job, *args) } 54 | else 55 | block.call(job, *args) 56 | end 57 | rescue StandardError => e 58 | report(e, job) 59 | 60 | raise e 61 | end 62 | end 63 | end 64 | 65 | def self.report(e, job) 66 | return if skip_report?(job) 67 | 68 | data = build_job_data(job) 69 | 70 | ::Rollbar.scope(:request => data) 71 | .error(e, :use_exception_level_filters => true) 72 | end 73 | 74 | def self.skip_report?(job) 75 | handler = ::Rollbar.configuration.async_skip_report_handler 76 | 77 | return handler.call(job) if handler.respond_to?(:call) 78 | 79 | job.attempts < ::Rollbar.configuration.dj_threshold 80 | end 81 | 82 | def self.build_job_data(job) 83 | return nil unless ::Rollbar.configuration.report_dj_data 84 | 85 | JobData.new(job).to_hash 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/error_context.rb: -------------------------------------------------------------------------------- 1 | module RollbarErrorContext 2 | attr_accessor :rollbar_context 3 | end 4 | 5 | Rollbar.plugins.define('error_context') do 6 | dependency { configuration.enable_error_context } 7 | 8 | execute! do 9 | StandardError.send(:include, RollbarErrorContext) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/goalie.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('goalie') do 2 | dependency { !configuration.disable_monkey_patch } 3 | dependency { defined?(Goalie) } 4 | 5 | execute do 6 | module Rollbar 7 | module Goalie 8 | def render_exception_with_rollbar(env, exception) 9 | exception_data = nil 10 | 11 | begin 12 | controller = env['action_controller.instance'] 13 | request_data = begin 14 | controller.rollbar_request_data 15 | rescue StandardError 16 | nil 17 | end 18 | person_data = begin 19 | controller.rollbar_person_data 20 | rescue StandardError 21 | nil 22 | end 23 | exception_data = Rollbar.scope( 24 | :request => request_data, 25 | :person => person_data 26 | ).error(exception, :use_exception_level_filters => true) 27 | rescue StandardError => e 28 | message = "[Rollbar] Exception while reporting exception to Rollbar: #{e}" 29 | Rollbar.log_warning(message) 30 | end 31 | 32 | # if an exception was reported, save uuid in the env 33 | # so it can be displayed to the user on the error page 34 | case exception_data 35 | when Hash 36 | env['rollbar.exception_uuid'] = exception_data[:uuid] 37 | Rollbar.log_info( 38 | "[Rollbar] Exception uuid saved in env: #{exception_data[:uuid]}" 39 | ) 40 | when 'disabled' 41 | Rollbar.log_info( 42 | '[Rollbar] Exception not reported because Rollbar is disabled' 43 | ) 44 | when 'ignored' 45 | Rollbar.log_info( 46 | '[Rollbar] Exception not reported because it was ignored' 47 | ) 48 | end 49 | 50 | # now continue as normal 51 | render_exception_without_rollbar(env, exception) 52 | end 53 | end 54 | end 55 | end 56 | 57 | execute do 58 | Goalie::CustomErrorPages.class_eval do 59 | include Rollbar::Goalie 60 | 61 | alias_method :render_exception_without_rollbar, :render_exception 62 | alias_method :render_exception, :render_exception_with_rollbar 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rack.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('rack') do 2 | dependency { !configuration.disable_monkey_patch } 3 | dependency { !configuration.disable_rack_monkey_patch } 4 | 5 | execute do 6 | if defined?(Rack::Builder) 7 | require 'rollbar/middleware/rack' 8 | require 'rollbar/middleware/rack/builder' 9 | Rack::Builder.send(:include, Rollbar::Middleware::Rack::Builder) 10 | end 11 | 12 | if defined?(Rack::Test::Session) 13 | require 'rollbar/middleware/rack' 14 | require 'rollbar/middleware/rack/test_session' 15 | Rack::Test::Session.send(:include, Rollbar::Middleware::Rack::TestSession) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rails/controller_methods.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/request_data_extractor' 2 | require 'rollbar/util' 3 | 4 | module Rollbar 5 | module Rails 6 | module ControllerMethods 7 | include RequestDataExtractor 8 | 9 | def rollbar_person_data 10 | user = nil 11 | unless Rollbar::Util.method_in_stack_twice(:rollbar_person_data, __FILE__) 12 | user = send(Rollbar.configuration.person_method) 13 | end 14 | 15 | # include id, username, email if non-empty 16 | if user 17 | { 18 | :id => (begin 19 | user.send(Rollbar.configuration.person_id_method) 20 | rescue StandardError 21 | nil 22 | end), 23 | :username => (begin 24 | user.send(Rollbar.configuration.person_username_method) 25 | rescue StandardError 26 | nil 27 | end), 28 | :email => (begin 29 | user.send(Rollbar.configuration.person_email_method) 30 | rescue StandardError 31 | nil 32 | end) 33 | } 34 | else 35 | {} 36 | end 37 | rescue NameError 38 | {} 39 | end 40 | 41 | def rollbar_request_data 42 | extract_request_data_from_rack(request.env) 43 | end 44 | 45 | # for backwards compatabilty with the old ratchetio-gem 46 | def ratchetio_person_data 47 | rollbar_person_data 48 | end 49 | 50 | # for backwards compatabilty with the old ratchetio-gem 51 | def ratchetio_request_data 52 | rollbar_request_data 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rails/error_subscriber.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | class ErrorSubscriber 3 | def report(error, handled:, severity:, context:, source: nil) 4 | # The default `nil` for capture_uncaught means `true`. so check for false. 5 | return unless handled || Rollbar.configuration.capture_uncaught != false 6 | 7 | extra = context.is_a?(Hash) ? context.deep_dup : {} 8 | extra[:custom_data_method_context] = source 9 | Rollbar.log(severity, error, extra) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rails/railtie30.rb: -------------------------------------------------------------------------------- 1 | require 'rails/railtie' 2 | require 'rollbar/plugins/rails/railtie_mixin' 3 | 4 | module Rollbar 5 | class Railtie < ::Rails::Railtie 6 | include Rollbar::RailtieMixin 7 | 8 | initializer 'rollbar.middleware.rails' do |app| 9 | require 'rollbar/middleware/rails/rollbar' 10 | require 'rollbar/middleware/rails/show_exceptions' 11 | 12 | app.config.middleware.insert_after ActionDispatch::ShowExceptions, 13 | Rollbar::Middleware::Rails::RollbarMiddleware 14 | ActionDispatch::ShowExceptions.send(:include, 15 | Rollbar::Middleware::Rails::ShowExceptions) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rails/railtie32.rb: -------------------------------------------------------------------------------- 1 | require 'rails/railtie' 2 | require 'rollbar/plugins/rails/railtie_mixin' 3 | 4 | module Rollbar 5 | class Railtie < ::Rails::Railtie 6 | include Rollbar::RailtieMixin 7 | 8 | initializer 'rollbar.middleware.rails' do |app| 9 | require 'rollbar/middleware/rails/rollbar' 10 | require 'rollbar/middleware/rails/show_exceptions' 11 | 12 | app.config.middleware.insert_after ActionDispatch::DebugExceptions, 13 | Rollbar::Middleware::Rails::RollbarMiddleware 14 | ActionDispatch::DebugExceptions.send(:include, 15 | Rollbar::Middleware::Rails::ShowExceptions) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rails/railtie_mixin.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module RailtieMixin 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | rake_tasks do 7 | require 'rollbar/rake_tasks' 8 | end 9 | 10 | initializer 'rollbar.configuration' do 11 | config.after_initialize do 12 | Rollbar.preconfigure do |config| 13 | config.default_logger = proc { ::Rails.logger } 14 | config.environment ||= ::Rails.env 15 | config.root ||= ::Rails.root 16 | config.framework = "Rails: #{::Rails::VERSION::STRING}" 17 | config.filepath ||= begin 18 | if ::Rails.application.class.respond_to?(:module_parent_name) 19 | "#{::Rails.application.class.module_parent_name}.rollbar" 20 | else 21 | "#{::Rails.application.class.parent_name}.rollbar" 22 | end 23 | end 24 | end 25 | end 26 | end 27 | 28 | initializer 'rollbar.controller_methods' do 29 | ActiveSupport.on_load(:action_controller) do 30 | # lazily load action_controller methods 31 | require 'rollbar/plugins/rails/controller_methods' 32 | include Rollbar::Rails::ControllerMethods 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/rake.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('rake') do 2 | require_dependency('rake') 3 | dependency { !configuration.disable_monkey_patch } 4 | dependency { defined?(Rake) } 5 | 6 | module Rollbar 7 | module Rake 8 | class << self 9 | attr_accessor :patched 10 | end 11 | 12 | module Handler 13 | def self.included(base) 14 | base.class_eval do 15 | alias_method :orig_display_error_message, :display_error_message 16 | alias_method :display_error_message, :display_error_message_with_rollbar 17 | end 18 | end 19 | 20 | def display_error_message_with_rollbar(ex) 21 | Rollbar.error(ex, :use_exception_level_filters => true) 22 | orig_display_error_message(ex) 23 | end 24 | end 25 | 26 | def self.patch! 27 | unless patch? 28 | skip_patch 29 | 30 | return 31 | end 32 | 33 | ::Rake.application.instance_eval do 34 | class << self 35 | include ::Rollbar::Rake::Handler 36 | end 37 | end 38 | 39 | self.patched = true 40 | end 41 | 42 | def self.skip_patch 43 | warn('[Rollbar] Rollbar is disabled for Rake tasks since your Rake ' \ 44 | 'version is under 0.9.x. Please upgrade to 0.9.x or higher.') 45 | end 46 | 47 | def self.patch? 48 | return false if patched? 49 | return false unless rake_version 50 | 51 | major, minor, = rake_version.split('.').map(&:to_i) 52 | 53 | major > 0 || major == 0 && minor > 8 54 | end 55 | 56 | def self.patched? 57 | patched 58 | end 59 | 60 | def self.rake_version 61 | if Object.const_defined?('RAKEVERSION') 62 | RAKEVERSION 63 | elsif ::Rake.const_defined?('VERSION') 64 | ::Rake::VERSION 65 | end 66 | end 67 | end 68 | end 69 | 70 | execute do 71 | Rollbar::Rake.patch! 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/resque.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('resque') do 2 | require_dependency('resque') 3 | 4 | # We want to have Resque::Failure::Rollbar loaded before 5 | # possible initializers, so the users can use the class 6 | # when configuring Rollbar::Failure.backend or 7 | # Rollbar::Failure::Multiple.classes 8 | execute! do 9 | require 'rollbar/plugins/resque/failure' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/resque/failure.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar' 2 | 3 | module Resque 4 | module Failure 5 | # Falure class to use in Resque in order to send 6 | # Resque errors to the Rollbar API 7 | class Rollbar < Base 8 | def save 9 | payload_with_options = 10 | if use_exception_level_filters? 11 | payload.merge(:use_exception_level_filters => true) 12 | else 13 | payload 14 | end 15 | 16 | rollbar.error(exception, payload_with_options) 17 | end 18 | 19 | private 20 | 21 | # We want to disable async reporting since original 22 | # resque-rollbar implementation disabled it. 23 | def rollbar 24 | notifier = ::Rollbar.notifier.scope 25 | notifier.configuration.use_async = false 26 | 27 | notifier 28 | end 29 | 30 | def use_exception_level_filters? 31 | Gem::Version.new(rollbar_version) > Gem::Version.new('1.3.0') 32 | end 33 | 34 | def rollbar_version 35 | ::Rollbar::VERSION 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/sidekiq.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('sidekiq >= 3') do 2 | require_dependency('sidekiq') 3 | dependency { !configuration.disable_monkey_patch } 4 | dependency { defined?(Sidekiq) } 5 | dependency { Sidekiq::VERSION.split('.')[0].to_i >= 3 } 6 | 7 | execute do 8 | require 'rollbar/plugins/sidekiq/plugin' 9 | 10 | Sidekiq.configure_server do |config| 11 | config.server_middleware do |chain| 12 | chain.add Rollbar::Sidekiq::ResetScope 13 | end 14 | 15 | config.error_handlers << proc do |e, context, _sidekiq_config = nil| 16 | Rollbar::Sidekiq.handle_exception(context, e) 17 | end 18 | end 19 | end 20 | end 21 | 22 | Rollbar.plugins.define('sidekiq < 3') do 23 | require_dependency('sidekiq') 24 | dependency { !configuration.disable_monkey_patch } 25 | dependency { defined?(Sidekiq) } 26 | dependency { Sidekiq::VERSION.split('.')[0].to_i < 3 } 27 | 28 | execute do 29 | require 'rollbar/plugins/sidekiq/plugin' 30 | 31 | Sidekiq.configure_server do |config| 32 | config.server_middleware do |chain| 33 | chain.add Rollbar::Sidekiq 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/sidekiq/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/scrubbers/params' 2 | 3 | module Rollbar 4 | class Sidekiq 5 | PARAM_BLACKLIST = %w[backtrace error_backtrace error_message error_class].freeze 6 | 7 | class ResetScope 8 | def call(_worker, msg, _queue, &block) 9 | Rollbar.reset_notifier! # clears scope 10 | 11 | return yield unless Rollbar.configuration.sidekiq_use_scoped_block 12 | 13 | Rollbar.scoped(Rollbar::Sidekiq.job_scope(msg), &block) 14 | end 15 | end 16 | 17 | def self.handle_exception(msg, e) 18 | return if skip_report?(msg, e) 19 | 20 | Rollbar.scope(job_scope(msg)).error(e, :use_exception_level_filters => true) 21 | end 22 | 23 | def self.skip_report?(msg, _e) 24 | job_hash = job_hash_from_msg(msg) 25 | 26 | return false if job_hash.nil? 27 | 28 | # when rollbar middleware catches, sidekiq's retry_job processor hasn't set 29 | # the retry_count for the current job yet, so adding 1 gives the actual retry count 30 | actual_retry_count = job_hash.fetch('retry_count', -1) + 1 31 | job_hash['retry'] && actual_retry_count < ::Rollbar.configuration.sidekiq_threshold 32 | end 33 | 34 | def self.job_scope(msg) 35 | scope = { 36 | :framework => "Sidekiq: #{::Sidekiq::VERSION}" 37 | } 38 | job_hash = job_hash_from_msg(msg) 39 | 40 | unless job_hash.nil? 41 | params = job_hash.reject { |k| PARAM_BLACKLIST.include?(k) } 42 | scope[:request] = { :params => scrub_params(params) } 43 | scope[:context] = params['class'] 44 | scope[:queue] = params['queue'] 45 | end 46 | 47 | scope 48 | end 49 | 50 | def self.scrub_params(params) 51 | options = { 52 | :params => params, 53 | :config => Rollbar.configuration.scrub_fields, 54 | :whitelist => Rollbar.configuration.scrub_whitelist 55 | } 56 | 57 | Rollbar::Scrubbers::Params.call(options) 58 | end 59 | 60 | # see https://github.com/mperham/sidekiq/wiki/Middleware#server-middleware 61 | def call(_worker, msg, _queue, &block) 62 | Rollbar.reset_notifier! # clears scope 63 | 64 | return yield unless Rollbar.configuration.sidekiq_use_scoped_block 65 | 66 | Rollbar.scoped(Rollbar::Sidekiq.job_scope(msg), &block) 67 | rescue Exception => e # rubocop:disable Lint/RescueException 68 | Rollbar::Sidekiq.handle_exception(msg, e) 69 | raise 70 | end 71 | 72 | def self.job_hash_from_msg(msg) 73 | msg && (msg[:job] || msg) 74 | end 75 | private_class_method :job_hash_from_msg 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/thread.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('thread') do 2 | module Rollbar 3 | module ThreadPlugin 4 | def initialize(*args) 5 | self[:_rollbar_notifier] ||= Rollbar.notifier.scope 6 | super 7 | end 8 | end 9 | end 10 | 11 | execute do 12 | Thread.send(:prepend, Rollbar::ThreadPlugin) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/rollbar/plugins/validations.rb: -------------------------------------------------------------------------------- 1 | Rollbar.plugins.define('active_model') do 2 | dependency { !configuration.disable_monkey_patch } 3 | dependency { defined?(ActiveModel::Validations) } 4 | dependency do 5 | require 'active_model/version' 6 | 7 | ActiveModel::VERSION::MAJOR >= 3 8 | end 9 | 10 | execute! do 11 | module Rollbar 12 | # Module that defines methods to be used by instances using 13 | # ActiveModel::Validations 14 | # The name is ActiveRecordExtension in order to not break backwards 15 | # compatibility, although probably it should be named 16 | # Rollbar::ValidationsExtension or similar 17 | module ActiveRecordExtension 18 | def report_validation_errors_to_rollbar 19 | errors.full_messages.each do |error| 20 | Rollbar.log_info( 21 | "[Rollbar] Reporting form validation error: #{error} for #{self}" 22 | ) 23 | Rollbar.warning("Form Validation Error: #{error} for #{self}") 24 | end 25 | end 26 | end 27 | end 28 | end 29 | 30 | execute! do 31 | ActiveModel::Validations.module_eval do 32 | include Rollbar::ActiveRecordExtension 33 | end 34 | 35 | active_support_was_defined = defined?(ActiveRecord::Base) 36 | 37 | ActiveSupport.on_load(:active_record) do 38 | if active_support_was_defined 39 | ActiveRecord::Base.class_eval do 40 | include Rollbar::ActiveRecordExtension 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/rollbar/rails.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Rails 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/rollbar/rake_tasks.rb: -------------------------------------------------------------------------------- 1 | namespace :rollbar do 2 | desc 'Verify your gem installation by sending a test message to Rollbar' 3 | task :test => [:environment] do 4 | rollbar_dir = Gem.loaded_specs['rollbar'].full_gem_path 5 | require "#{rollbar_dir}/lib/rollbar/rollbar_test" 6 | 7 | RollbarTest.run 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/rollbar/rollbar_test.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar' 2 | 3 | module RollbarTest # :nodoc: 4 | def self.run 5 | return unless confirmed_token? 6 | 7 | puts 'Test sending to Rollbar...' 8 | result = Rollbar.info('Test message from rollbar:test') 9 | 10 | if result == 'error' 11 | puts error_message 12 | else 13 | puts success_message 14 | end 15 | end 16 | 17 | def self.confirmed_token? 18 | return true if Rollbar.configuration.access_token 19 | 20 | puts token_error_message 21 | 22 | false 23 | end 24 | 25 | def self.token_error_message 26 | 'Rollbar needs an access token configured. Check the README for instructions.' 27 | end 28 | 29 | def self.error_message 30 | 'Test failed! You may have a configuration issue, or you could be using a ' \ 31 | 'gem that\'s blocking the test. Contact support@rollbar.com if you need ' \ 32 | 'help troubleshooting.' 33 | end 34 | 35 | def self.success_message 36 | 'Testing rollbar with "rake rollbar:test". If you can see this, it works.' 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/rollbar/scrubbers.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Scrubbers 3 | module_function 4 | 5 | def scrub_value(_value) 6 | if Rollbar.configuration.randomize_scrub_length 7 | random_filtered_value 8 | else 9 | '*' * 6 10 | end 11 | end 12 | 13 | def random_filtered_value 14 | '*' * rand(3..7) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rollbar/truncation.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/util' 2 | require 'rollbar/truncation/mixin' 3 | require 'rollbar/truncation/raw_strategy' 4 | require 'rollbar/truncation/frames_strategy' 5 | require 'rollbar/truncation/strings_strategy' 6 | require 'rollbar/truncation/min_body_strategy' 7 | require 'rollbar/truncation/remove_request_strategy' 8 | require 'rollbar/truncation/remove_extra_strategy' 9 | require 'rollbar/truncation/remove_any_key_strategy' 10 | 11 | module Rollbar 12 | module Truncation 13 | extend ::Rollbar::Truncation::Mixin 14 | 15 | MAX_PAYLOAD_SIZE = 512 * 1024 # 512kb 16 | STRATEGIES = [RawStrategy, 17 | FramesStrategy, 18 | StringsStrategy, 19 | MinBodyStrategy, 20 | RemoveRequestStrategy, 21 | RemoveExtraStrategy, 22 | RemoveAnyKeyStrategy].freeze 23 | 24 | def self.truncate(payload, attempts = []) 25 | result = nil 26 | 27 | STRATEGIES.each do |strategy| 28 | result = strategy.call(payload) 29 | attempts << result.bytesize 30 | break unless truncate?(result) 31 | end 32 | 33 | result 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/frames_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/truncation/mixin' 2 | require 'rollbar/util' 3 | 4 | module Rollbar 5 | module Truncation 6 | class FramesStrategy 7 | include ::Rollbar::Truncation::Mixin 8 | 9 | def self.call(payload) 10 | new.call(payload) 11 | end 12 | 13 | def call(payload) 14 | new_payload = payload 15 | body = new_payload['data']['body'] 16 | 17 | if body['trace_chain'] 18 | truncate_trace_chain(body) 19 | elsif body['trace'] 20 | truncate_trace(body) 21 | end 22 | 23 | dump(new_payload) 24 | end 25 | 26 | def truncate_trace(body) 27 | trace_data = body['trace'] 28 | frames = trace_data['frames'] 29 | trace_data['frames'] = select_frames(frames) 30 | 31 | body['trace']['frames'] = select_frames(body['trace']['frames']) 32 | end 33 | 34 | def truncate_trace_chain(body) 35 | chain = body['trace_chain'] 36 | 37 | body['trace_chain'] = chain.map do |trace_data| 38 | frames = trace_data['frames'] 39 | trace_data['frames'] = select_frames(frames) 40 | trace_data 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/min_body_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/truncation/mixin' 2 | require 'rollbar/util' 3 | 4 | module Rollbar 5 | module Truncation 6 | class MinBodyStrategy 7 | include ::Rollbar::Truncation::Mixin 8 | 9 | def self.call(payload) 10 | new.call(payload) 11 | end 12 | 13 | def call(payload) 14 | body = payload['data']['body'] 15 | 16 | if body['trace_chain'] 17 | body['trace_chain'] = body['trace_chain'].map do |trace_data| 18 | truncate_trace_data(trace_data) 19 | end 20 | elsif body['trace'] 21 | body['trace'] = truncate_trace_data(body['trace']) 22 | end 23 | 24 | dump(payload) 25 | end 26 | 27 | def truncate_trace_data(trace_data) 28 | trace_data['exception'].delete('description') 29 | trace_data['exception']['message'] = trace_data['exception']['message'][0, 255] 30 | trace_data['frames'] = select_frames(trace_data['frames'], 1) 31 | 32 | trace_data 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/mixin.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Truncation 3 | module Mixin 4 | def dump(payload) 5 | Rollbar::JSON.dump(payload) 6 | end 7 | 8 | def truncate?(result) 9 | result.bytesize > MAX_PAYLOAD_SIZE 10 | end 11 | 12 | def select_frames(frames, range = 50) 13 | return frames unless frames.count > range * 2 14 | 15 | frames[0, range] + frames[-range, range] 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/raw_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/truncation/mixin' 2 | 3 | module Rollbar 4 | module Truncation 5 | class RawStrategy 6 | include ::Rollbar::Truncation::Mixin 7 | 8 | def self.call(payload) 9 | new.call(payload) 10 | end 11 | 12 | def call(payload) 13 | dump(payload) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/remove_extra_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/util' 2 | 3 | module Rollbar 4 | module Truncation 5 | class RemoveExtraStrategy 6 | include ::Rollbar::Truncation::Mixin 7 | 8 | def self.call(payload) 9 | new.call(payload) 10 | end 11 | 12 | def call(payload) 13 | body = payload['data']['body'] 14 | 15 | delete_message_extra(body) 16 | delete_trace_chain_extra(body) 17 | delete_trace_extra(body) 18 | 19 | dump(payload) 20 | end 21 | 22 | def delete_message_extra(body) 23 | body['message'].delete('extra') if body['message'] && body['message']['extra'] 24 | end 25 | 26 | def delete_trace_chain_extra(body) 27 | return unless body['trace_chain'] && body['trace_chain'][0]['extra'] 28 | 29 | body['trace_chain'][0].delete('extra') 30 | end 31 | 32 | def delete_trace_extra(body) 33 | body['trace'].delete('extra') if body['trace'] && body['trace']['extra'] 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/remove_request_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/util' 2 | 3 | module Rollbar 4 | module Truncation 5 | class RemoveRequestStrategy 6 | include ::Rollbar::Truncation::Mixin 7 | 8 | def self.call(payload) 9 | new.call(payload) 10 | end 11 | 12 | def call(payload) 13 | data = payload['data'] 14 | 15 | data.delete('request') if data['request'] 16 | 17 | dump(payload) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/rollbar/truncation/strings_strategy.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/util' 2 | require 'rollbar/truncation/mixin' 3 | 4 | module Rollbar 5 | module Truncation 6 | class StringsStrategy 7 | include ::Rollbar::Truncation::Mixin 8 | 9 | STRING_THRESHOLDS = [1024, 512, 256, 128].freeze 10 | 11 | def self.call(payload) 12 | new.call(payload) 13 | end 14 | 15 | def call(payload) 16 | result = nil 17 | 18 | STRING_THRESHOLDS.each do |threshold| 19 | truncate_proc = truncate_strings_proc(threshold) 20 | 21 | ::Rollbar::Util.iterate_and_update(payload, truncate_proc) 22 | result = dump(payload) 23 | 24 | break unless truncate?(result) 25 | end 26 | 27 | result 28 | end 29 | 30 | def truncate_strings_proc(threshold) 31 | proc do |value| 32 | # Rollbar::Util.truncate will operate on characters, not bytes, 33 | # so use value.length, not bytesize. 34 | if value.is_a?(String) && value.length > threshold 35 | Rollbar::Util.truncate(value, threshold) 36 | else 37 | value 38 | end 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/rollbar/util/hash.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Util 3 | module Hash # :nodoc: 4 | def self.deep_stringify_keys(hash, seen = {}) 5 | seen.compare_by_identity 6 | return if seen[hash] 7 | 8 | seen[hash] = true 9 | replace_seen_children(hash, seen) 10 | 11 | hash.reduce({}) do |h, (key, value)| 12 | h[key.to_s] = map_value(value, :deep_stringify_keys, seen) 13 | 14 | h 15 | end 16 | end 17 | 18 | def self.map_value(thing, meth, seen) 19 | case thing 20 | when ::Hash 21 | send(meth, thing, seen) 22 | when Array 23 | if seen[thing] 24 | thing 25 | else 26 | seen[thing] = true 27 | replace_seen_children(thing, seen) 28 | thing.map { |v| map_value(v, meth, seen) } 29 | end 30 | else 31 | thing 32 | end 33 | end 34 | 35 | def self.replace_seen_children(thing, seen) 36 | case thing 37 | when ::Hash 38 | thing.keys.each do |key| # rubocop:disable Style/HashEachMethods 39 | if seen[thing[key]] 40 | thing[key] = 41 | "removed circular reference: #{thing[key]}" 42 | end 43 | end 44 | when Array 45 | thing.each_with_index do |_, i| 46 | if seen[thing[i]] 47 | thing[i] = 48 | "removed circular reference: #{thing[i]}" 49 | end 50 | end 51 | end 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/rollbar/util/ip_anonymizer.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Util 3 | module IPAnonymizer 4 | require 'ipaddr' 5 | 6 | def self.anonymize_ip(ip_string) 7 | return ip_string unless Rollbar.configuration.anonymize_user_ip 8 | 9 | ip = IPAddr.new(ip_string) 10 | return anonymize_ipv6 ip if ip.ipv6? 11 | return anonymize_ipv4 ip if ip.ipv4? 12 | rescue StandardError 13 | nil 14 | end 15 | 16 | def self.anonymize_ipv4(ip) 17 | ip_parts = ip.to_s.split '.' 18 | 19 | ip_parts[ip_parts.count - 1] = '0' 20 | 21 | IPAddr.new(ip_parts.join('.')).to_s 22 | end 23 | 24 | def self.anonymize_ipv6(ip) 25 | ip_parts = ip.to_s.split ':' 26 | 27 | ip_string = "#{ip_parts[0..2].join(':')}:0000:0000:0000:0000:0000" 28 | 29 | IPAddr.new(ip_string).to_s 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/rollbar/util/ip_obfuscator.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | module Util 3 | module IPObfuscator 4 | require 'ipaddr' 5 | require 'digest' 6 | 7 | def self.obfuscate_ip(ip_string) 8 | return ip_string unless Rollbar.configuration.user_ip_obfuscator_secret 9 | 10 | secret = Rollbar.configuration.user_ip_obfuscator_secret 11 | ip_int32 = IPAddr.new(ip_string, Socket::AF_INET).to_i 12 | secret_int32 = Digest::MD5.hexdigest(secret)[0..7].to_i(16) 13 | obfuscated_ip_int32 = ip_int32 ^ secret_int32 % (2 << 31) 14 | 15 | IPAddr.new(obfuscated_ip_int32, Socket::AF_INET).to_s 16 | rescue StandardError 17 | nil 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/rollbar/version.rb: -------------------------------------------------------------------------------- 1 | module Rollbar 2 | VERSION = '3.6.2'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/tasks/tasks.rake: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | desc 'Update rollbar.js snippet' 4 | task :update_snippet do 5 | input_path = File.expand_path('../../../rollbar.js/dist/rollbar.snippet.js', __FILE__) 6 | output_path = File.expand_path('../../../data/rollbar.snippet.js', __FILE__) 7 | output_dir = File.expand_path('../../../data/', __FILE__) 8 | 9 | $stdout.write("Copying #{input_path} to #{output_path}\n") 10 | 11 | FileUtils.mkdir_p(output_dir) 12 | FileUtils.copy(input_path, output_path) 13 | end 14 | -------------------------------------------------------------------------------- /rollbar.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require File.expand_path('../lib/rollbar/version', __FILE__) 4 | 5 | Gem::Specification.new do |gem| 6 | _is_jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby') 7 | 8 | gem.authors = ['Rollbar, Inc.'] 9 | gem.email = ['support@rollbar.com'] 10 | gem.description = "Track and debug errors in your Ruby applications with ease using Rollbar. With this gem, you can easily monitor and report on exceptions and other errors in your code, helping you identify and fix issues more quickly. Rollbar's intuitive interface and advanced error tracking features make it the perfect tool for ensuring the stability and reliability of your Ruby applications." 11 | gem.executables = ['rollbar-rails-runner'] 12 | gem.summary = 'Reports exceptions to Rollbar' 13 | gem.homepage = 'https://rollbar.com' 14 | gem.license = 'MIT' 15 | gem.files = `git ls-files -z`.split("\x0").reject do |f| 16 | f.match(%r{^(test|spec|features)/}) 17 | end 18 | gem.files += ['spec/support/rollbar_api.rb'] # useful helper for app spec/tests. 19 | gem.name = 'rollbar' 20 | gem.require_paths = ['lib'] 21 | gem.required_ruby_version = '>= 2.0.0' 22 | gem.version = Rollbar::VERSION 23 | 24 | if gem.respond_to?(:metadata) 25 | gem.metadata['changelog_uri'] = 'https://github.com/rollbar/rollbar-gem/releases' 26 | gem.metadata['source_code_uri'] = 'https://github.com/rollbar/rollbar-gem' 27 | gem.metadata['bug_tracker_uri'] = 'https://github.com/rollbar/rollbar-gem/issues' 28 | gem.metadata['homepage_uri'] = 'https://rollbar.com/' 29 | gem.metadata['documentation_uri'] = 'https://docs.rollbar.com/docs/ruby' 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/commands/rollbar_rails_runner_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | if defined?(RSpecCommand) 4 | require 'rails/rollbar_runner' 5 | 6 | describe 'rollbar-rails-runner', :if => RUBY_VERSION < '2.6' do 7 | command %q[rollbar-rails-runner "puts 'hello'"] 8 | its(:stdout) do 9 | is_expected.to include('hello') 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/delay/sidekiq_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | begin 4 | require 'rollbar/delay/sidekiq' 5 | require 'sidekiq/testing' 6 | rescue LoadError 7 | module Rollbar 8 | module Delay 9 | class Sidekiq 10 | end 11 | end 12 | end 13 | end 14 | 15 | describe Rollbar::Delay::Sidekiq do 16 | let(:payload) {{ 'foo' => 'bar' }} 17 | 18 | describe '#perform' do 19 | it 'performs payload' do 20 | Rollbar.should_receive(:process_from_async_handler).with(payload) 21 | subject.perform payload 22 | end 23 | end 24 | 25 | describe '#call' do 26 | shared_examples 'a Rollbar processor' do 27 | it 'processes payload' do 28 | Rollbar.should_receive(:process_from_async_handler).with(payload) 29 | 30 | subject.call payload 31 | described_class.drain 32 | end 33 | end 34 | 35 | context 'with default options' do 36 | it 'enqueues to default queue' do 37 | options = Rollbar::Delay::Sidekiq::OPTIONS.merge('args' => [payload]) 38 | ::Sidekiq::Client.should_receive(:push).with(options) { true } 39 | 40 | subject.call payload 41 | end 42 | 43 | it_behaves_like 'a Rollbar processor' 44 | end 45 | 46 | context 'with custom options' do 47 | let(:custom_config) { { 'queue' => 'custom_queue' } } 48 | subject { Rollbar::Delay::Sidekiq.new custom_config } 49 | 50 | it 'enqueues to custom queue' do 51 | options = Rollbar::Delay::Sidekiq::OPTIONS.merge( 52 | custom_config.merge('args' => [payload]) 53 | ) 54 | ::Sidekiq::Client.should_receive(:push).with(options) { true } 55 | 56 | subject.call payload 57 | end 58 | 59 | it_behaves_like 'a Rollbar processor' 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/delay/sucker_punch_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | begin 4 | require 'rollbar/delay/sucker_punch' 5 | require 'sucker_punch/testing/inline' 6 | rescue LoadError 7 | module Rollbar 8 | module Delay 9 | class SuckerPunch 10 | end 11 | end 12 | end 13 | end 14 | 15 | describe Rollbar::Delay::SuckerPunch do 16 | describe '.call' do 17 | let(:payload) { 'anything' } 18 | 19 | it 'performs the task asynchronously' do 20 | Rollbar.should_receive(:process_from_async_handler) 21 | 22 | Rollbar::Delay::SuckerPunch.call(payload) 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/delayed/serialization/test.rb: -------------------------------------------------------------------------------- 1 | # The tests at spec/rollbar/plugins/delayed_job_spec.rb 2 | # expect to find a file here. 3 | -------------------------------------------------------------------------------- /spec/dummyapp/.gitignore: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------------- 2 | # Ignore these files when commiting to a git repository. 3 | # 4 | # See http://help.github.com/ignore-files/ for more about ignoring files. 5 | # 6 | # The original version of this file is found here: 7 | # https://github.com/RailsApps/rails-composer/blob/master/files/gitignore.txt 8 | # 9 | # Corrections? Improvements? Create a GitHub issue: 10 | # http://github.com/RailsApps/rails-composer/issues 11 | #---------------------------------------------------------------------------- 12 | 13 | # bundler state 14 | /.bundle 15 | /vendor/bundle/ 16 | /vendor/ruby/ 17 | 18 | # minimal Rails specific artifacts 19 | db/*.sqlite3 20 | /log/* 21 | /tmp/* 22 | 23 | # various artifacts 24 | **/*.war 25 | *.rbc 26 | *.sassc 27 | .rspec 28 | .redcar/ 29 | .sass-cache 30 | /config/config.yml 31 | /coverage.data 32 | /coverage/ 33 | /db/*.javadb/ 34 | /db/*.sqlite3 35 | /doc/api/ 36 | /doc/app/ 37 | /doc/features.html 38 | /doc/specs.html 39 | /public/cache 40 | /public/stylesheets/compiled 41 | /public/system/* 42 | /spec/tmp/* 43 | /cache 44 | /capybara* 45 | /capybara-*.html 46 | /gems 47 | /specifications 48 | rerun.txt 49 | pickle-email-*.html 50 | 51 | # If you find yourself ignoring temporary files generated by your text editor 52 | # or operating system, you probably want to add a global ignore instead: 53 | # git config --global core.excludesfile ~/.gitignore_global 54 | # 55 | # Here are some files you may want to ignore globally: 56 | 57 | # scm revert files 58 | **/*.orig 59 | 60 | # Mac finder artifacts 61 | .DS_Store 62 | 63 | # Netbeans project directory 64 | /nbproject/ 65 | 66 | # RubyMine project files 67 | .idea 68 | 69 | # Textmate project files 70 | /*.tmproj 71 | 72 | # vim artifacts 73 | **/*.swp 74 | -------------------------------------------------------------------------------- /spec/dummyapp/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /spec/dummyapp/app/assets/config/manifest.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbar/rollbar-gem/4694a35aba7518b30097a41fab15653d07cd73c0/spec/dummyapp/app/assets/config/manifest.js -------------------------------------------------------------------------------- /spec/dummyapp/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery_ujs 3 | //= require_tree . 4 | -------------------------------------------------------------------------------- /spec/dummyapp/app/assets/stylesheets/application.css.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | .brand { 15 | float: left; 16 | padding-right: 8px; 17 | } 18 | ul.nav { 19 | list-style: none; 20 | margin: 0 0 2em; 21 | padding: 0; 22 | } 23 | ul.nav li { 24 | display: inline; 25 | } 26 | #flash_notice, #flash_alert { 27 | padding: 5px 8px; 28 | margin: 10px 0; 29 | } 30 | #flash_notice { 31 | background-color: #CFC; 32 | border: solid 1px #6C6; 33 | } 34 | #flash_alert { 35 | background-color: #FCC; 36 | border: solid 1px #C66; 37 | } 38 | -------------------------------------------------------------------------------- /spec/dummyapp/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummyapp/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | @users = User.all 4 | 5 | Rollbar.debug('Test message from controller with no data') 6 | Rollbar.debug('Test message from controller with extra data', 7 | :foo => 'bar', :num_users => @users.length) 8 | end 9 | 10 | def report_exception 11 | _foo = bar 12 | rescue StandardError => e 13 | Rollbar.error(e) 14 | end 15 | 16 | def deprecated_report_exception 17 | begin 18 | _foo = bar 19 | rescue StandardError => e 20 | Rollbar.error(e) 21 | end 22 | render :json => {} 23 | end 24 | 25 | def handle_rails_error 26 | Rails.error.handle do 27 | raise 'Handle Rails error' 28 | end 29 | 30 | render :json => {} 31 | end 32 | 33 | def record_rails_error 34 | Rails.error.record do 35 | raise 'Record Rails error' 36 | end 37 | end 38 | 39 | def cause_exception 40 | raise NameError, 'Uncaught Rails error' 41 | end 42 | 43 | def cause_exception_with_locals 44 | foo = false 45 | 46 | enumerator_using_fibers if params[:test_fibers] 47 | 48 | (0..2).each do |index| 49 | foo = Post 50 | 51 | build_hash_with_locals(foo, index) 52 | end 53 | end 54 | 55 | def enumerator_using_fibers 56 | # Calling each without a block returns an Iterator. 57 | # Calling #next on the iterator causes execution on a fiber. 58 | [1, 2, 3].each.next 59 | end 60 | 61 | def build_hash_with_locals(foo, _index) 62 | foo.tap do |obj| 63 | password = '123456' 64 | hash = { :foo => obj, :bar => 'bar' } 65 | hash.invalid_method 66 | end 67 | end 68 | 69 | def test_rollbar_js 70 | render 'js/test', :layout => 'simple' 71 | end 72 | 73 | def test_rollbar_js_with_nonce 74 | # Cause a secure_headers nonce to be added to script_src 75 | ::SecureHeaders.content_security_policy_script_nonce(request) 76 | 77 | render 'js/test', :layout => 'simple' 78 | end 79 | 80 | def file_upload 81 | _this = will_crash 82 | end 83 | 84 | def set_session_data 85 | session[:some_value] = 'this-is-a-cool-value' 86 | 87 | render :json => {} 88 | end 89 | 90 | def use_session_data 91 | _oh = this_is_crashing! 92 | end 93 | 94 | def current_user 95 | @current_user ||= User.find_by_id(cookies[:session_id]) 96 | end 97 | 98 | def custom_current_user 99 | user = User.new 100 | user.id = 123 101 | user.username = 'test' 102 | user.email = 'email@test.com' 103 | user 104 | end 105 | 106 | def recursive_current_user 107 | Rollbar.error('Recurisve call to rollbar') 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /spec/dummyapp/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | respond_to?(:before_action) ? (before_action :authenticate_user!) : (before_filter :authenticate_user!) 3 | 4 | def index 5 | @users = User.all 6 | end 7 | 8 | def show 9 | @user = User.find(params[:id]) 10 | end 11 | 12 | def start_session 13 | @user = User.find(params[:id]) 14 | cookies[:session_id] = @user.encrypted_password 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/dummyapp/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbar/rollbar-gem/4694a35aba7518b30097a41fab15653d07cd73c0/spec/dummyapp/app/helpers/.gitkeep -------------------------------------------------------------------------------- /spec/dummyapp/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbar/rollbar-gem/4694a35aba7518b30097a41fab15653d07cd73c0/spec/dummyapp/app/mailers/.gitkeep -------------------------------------------------------------------------------- /spec/dummyapp/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbar/rollbar-gem/4694a35aba7518b30097a41fab15653d07cd73c0/spec/dummyapp/app/models/.gitkeep -------------------------------------------------------------------------------- /spec/dummyapp/app/models/book.rb: -------------------------------------------------------------------------------- 1 | class Book < ActiveRecord::Base 2 | belongs_to :user 3 | 4 | after_validation :report_validation_errors_to_rollbar 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummyapp/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post 2 | include ActiveModel::Validations 3 | include ActiveModel::Validations::Callbacks 4 | 5 | attr_accessor :title 6 | 7 | validates_presence_of :title 8 | after_validation :report_validation_errors_to_rollbar 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummyapp/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | if Rails::VERSION::MAJOR < 4 3 | attr_accessible :username, :email, :password, :password_confirmation, 4 | :remember_me 5 | end 6 | 7 | validates_presence_of :email 8 | after_validation :report_validation_errors_to_rollbar 9 | end 10 | -------------------------------------------------------------------------------- /spec/dummyapp/app/views/devise/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 |
<%= f.label :name %>
6 | <%= f.text_field :name %>
Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %>.
26 | 27 | <%= link_to "Back", :back %> 28 | -------------------------------------------------------------------------------- /spec/dummyapp/app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |<%= f.label :name %>
6 | <%= f.text_field :name %>
User: <%=link_to user.name, user %>
4 | <% end %> -------------------------------------------------------------------------------- /spec/dummyapp/app/views/home/report_exception.html.erb: -------------------------------------------------------------------------------- 1 | Reported an exception. 2 | -------------------------------------------------------------------------------- /spec/dummyapp/app/views/js/test.html.erb: -------------------------------------------------------------------------------- 1 | Testing Rollbar JS 2 | -------------------------------------------------------------------------------- /spec/dummyapp/app/views/layouts/_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% flash.each do |name, msg| %> 2 | <% if msg.is_a?(String) %> 3 | <%= content_tag :div, msg, :id => "flash_#{name}" %> 4 | <% end %> 5 | <% end %> -------------------------------------------------------------------------------- /spec/dummyapp/app/views/layouts/_navigation.html.erb: -------------------------------------------------------------------------------- 1 | <%= link_to "Dummyapp", root_path, :class => 'brand' %> 2 | -------------------------------------------------------------------------------- /spec/dummyapp/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |User: <%= @user.name %>
3 |Email: <%= @user.email if @user.email %>
-------------------------------------------------------------------------------- /spec/dummyapp/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Dummyapp::Application 5 | -------------------------------------------------------------------------------- /spec/dummyapp/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # If not already set, use the default. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 5 | 6 | if File.exist?(ENV['BUNDLE_GEMFILE']) 7 | require 'bundler' 8 | Bundler.setup 9 | end 10 | 11 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) 12 | -------------------------------------------------------------------------------- /spec/dummyapp/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /spec/dummyapp/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Dummy::Application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummyapp/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Raise exception on mass assignment protection for Active Record models 26 | # config.active_record.mass_assignment_sanitizer = :strict 27 | 28 | # Log the query plan for queries taking more than this (works 29 | # with SQLite, MySQL, and PostgreSQL) 30 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 31 | 32 | # Do not compress assets 33 | # config.assets.compress = false 34 | 35 | # Expands the lines which load the assets 36 | # config.assets.debug = true 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummyapp/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | # Log the query plan for queries taking more than this (works 65 | # with SQLite, MySQL, and PostgreSQL) 66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 67 | end 68 | -------------------------------------------------------------------------------- /spec/dummyapp/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = 'public, max-age=3600' 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = ENV['LOCAL'] == '1' 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | # config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | end 38 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 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 16 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 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 6 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/rollbar.rb: -------------------------------------------------------------------------------- 1 | Rollbar.configure do |config| 2 | config.access_token = 'aaaabbbbccccddddeeeeffff00001111' 3 | config.open_timeout = 60 4 | config.request_timeout = 60 5 | config.js_enabled = true 6 | config.js_options = { 7 | :foo => :bar 8 | } 9 | # By default, Rollbar will try to call the `current_user` controller method 10 | # to fetch the logged-in user object, and then call that object's `id` 11 | # method to fetch this property. To customize: 12 | # config.person_method = "my_current_user" 13 | # config.person_id_method = "my_id" 14 | 15 | # Additionally, you may specify the following: 16 | # config.person_username_method = "username" 17 | # config.person_email_method = "email" 18 | 19 | # Add exception class names to the exception_level_filters hash to 20 | # change the level that exception is reported at. Note that if an exception 21 | # has already been reported and logged the level will need to be changed 22 | # via the rollbar interface. 23 | # Valid levels: 'critical', 'error', 'warning', 'info', 'debug', 'ignore' 24 | # 'ignore' will cause the exception to not be reported at all. 25 | # config.exception_level_filters.merge!('MyCriticalException' => 'critical') 26 | end 27 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 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' 8 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 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 9 | -------------------------------------------------------------------------------- /spec/dummyapp/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 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] if defined?(wrap_parameters) 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 15 | -------------------------------------------------------------------------------- /spec/dummyapp/config/locales/en.yml: -------------------------------------------------------------------------------- 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" 6 | -------------------------------------------------------------------------------- /spec/dummyapp/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | root :to => 'home#index' 3 | resources :users do 4 | member { post :start_session } 5 | end 6 | 7 | match '/handle_rails_error' => 'home#handle_rails_error', :via => [:get, :post] 8 | match '/record_rails_error' => 'home#record_rails_error', :via => [:get, :post] 9 | match '/cause_exception' => 'home#cause_exception', :via => [:get, :post] 10 | match '/cause_exception_with_locals' => 'home#cause_exception_with_locals', 11 | :via => [:get, :post] 12 | put '/deprecated_report_exception' => 'home#deprecated_report_exception' 13 | match '/report_exception' => 'home#report_exception', 14 | :via => [:get, :post, :put] 15 | get '/current_user' => 'home#current_user' 16 | post '/file_upload' => 'home#file_upload' 17 | 18 | get '/set_session_data' => 'home#set_session_data' 19 | get '/use_session_data' => 'home#use_session_data' 20 | get '/test_rollbar_js' => 'home#test_rollbar_js' 21 | get '/test_rollbar_js_with_nonce' => 'home#test_rollbar_js_with_nonce' 22 | end 23 | -------------------------------------------------------------------------------- /spec/dummyapp/config/secrets.yml: -------------------------------------------------------------------------------- 1 | test: 2 | secret_key_base: 9ed31a007124058789d898117509a68022a0c5045ef3fd19e228139985d7f4365d1a908aeedbc9e0ad33c2cd62d765bccfb2b19b6cb06f4f7f2ac8a059adee91 -------------------------------------------------------------------------------- /spec/dummyapp/config/storage.yml: -------------------------------------------------------------------------------- 1 | # This isn't used, but is expected to be present for Rails 6.x 2 | test: 3 | service: Disk 4 | root: <%= Rails.root.join("tmp/storage") %> 5 | -------------------------------------------------------------------------------- /spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb: -------------------------------------------------------------------------------- 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 | t.timestamps 37 | end 38 | 39 | add_index :users, :email, :unique => true 40 | add_index :users, :reset_password_token, :unique => true 41 | # add_index :users, :confirmation_token, :unique => true 42 | # add_index :users, :unlock_token, :unique => true 43 | # add_index :users, :authentication_token, :unique => true 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummyapp/db/migrate/20161219184410_create_books.rb: -------------------------------------------------------------------------------- 1 | class CreateBooks < ActiveRecord::Migration 2 | def change 3 | create_table :books do |t| 4 | t.string :title 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/dummyapp/db/migrate/20161219185529_add_username_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddUsernameToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :username, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/dummyapp/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(:version => 20_161_219_185_529) do 14 | create_table 'books', :force => :cascade do |t| 15 | t.string 'title' 16 | t.integer 'user_id' 17 | t.datetime 'created_at', :null => false 18 | t.datetime 'updated_at', :null => false 19 | end 20 | 21 | create_table 'users', :force => :cascade do |t| 22 | t.string 'email', :default => '', :null => false 23 | t.string 'encrypted_password', :default => '', :null => false 24 | t.string 'reset_password_token' 25 | t.datetime 'reset_password_sent_at' 26 | t.datetime 'remember_created_at' 27 | t.integer 'sign_in_count', :default => 0 28 | t.datetime 'current_sign_in_at' 29 | t.datetime 'last_sign_in_at' 30 | t.string 'current_sign_in_ip' 31 | t.string 'last_sign_in_ip' 32 | t.datetime 'created_at' 33 | t.datetime 'updated_at' 34 | t.string 'name' 35 | t.string 'username' 36 | end 37 | 38 | add_index 'users', ['email'], :name => 'index_users_on_email', :unique => true 39 | add_index 'users', ['reset_password_token'], 40 | :name => 'index_users_on_reset_password_token', :unique => true 41 | end 42 | -------------------------------------------------------------------------------- /spec/dummyapp/db/seeds.rb: -------------------------------------------------------------------------------- 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! :username => 'user1', :email => 'user@example.com' 10 | puts "New user created: #{user.username}" 11 | user2 = User.create! :username => 'user2', :email => 'user2@example.com' 12 | puts "New user created: #{user2.username}" 13 | -------------------------------------------------------------------------------- /spec/dummyapp/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbar/rollbar-gem/4694a35aba7518b30097a41fab15653d07cd73c0/spec/dummyapp/lib/assets/.gitkeep -------------------------------------------------------------------------------- /spec/dummyapp/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |You may have mistyped the address or the page may have moved.
24 |Maybe you tried to change something you didn't have access to.
24 |