├── .rspec ├── spec ├── apps │ ├── rails │ │ ├── logs │ │ │ └── .gitkeep │ │ ├── dummy_task.rake │ │ └── dummy_app.rb │ ├── sinatra │ │ └── dummy_app.rb │ └── rack │ │ └── dummy_app.rb ├── integration │ ├── sinatra │ │ └── sinatra_spec.rb │ ├── rack │ │ └── rack_spec.rb │ ├── shared_examples │ │ └── rack_examples.rb │ └── rails │ │ ├── rails_spec.rb │ │ └── rake_spec.rb ├── airbrake_spec.rb ├── unit │ ├── sidekiq │ │ └── error_handler_spec.rb │ ├── rake │ │ └── tasks_spec.rb │ └── rack │ │ ├── middleware_spec.rb │ │ ├── notice_builder_spec.rb │ │ └── user_spec.rb └── spec_helper.rb ├── Gemfile ├── lib ├── airbrake │ ├── version.rb │ ├── resque │ │ └── failure.rb │ ├── rails │ │ ├── active_job.rb │ │ ├── action_controller.rb │ │ ├── active_record.rb │ │ └── railtie.rb │ ├── sidekiq │ │ └── error_handler.rb │ ├── delayed_job │ │ └── plugin.rb │ ├── rack │ │ ├── user.rb │ │ ├── middleware.rb │ │ └── notice_builder.rb │ ├── rake │ │ ├── task_ext.rb │ │ └── tasks.rb │ └── capistrano │ │ └── tasks.rb ├── generators │ ├── airbrake_generator.rb │ └── airbrake_initializer.rb.erb └── airbrake.rb ├── gemfiles ├── rack.gemfile ├── sinatra.gemfile ├── rails_3.2.gemfile ├── rails_4.0.gemfile ├── rails_4.1.gemfile ├── rails_4.2.gemfile └── rails_edge.gemfile ├── .gitignore ├── Rakefile ├── LICENSE.md ├── .rubocop.yml ├── airbrake.gemspec ├── CONTRIBUTING.md ├── Appraisals ├── CHANGELOG.md ├── circle.yml ├── README.md └── docs ├── Migration_guide_from_v4_to_v5.md └── CHANGELOG-pre-v5.txt /.rspec: -------------------------------------------------------------------------------- 1 | --warnings 2 | -------------------------------------------------------------------------------- /spec/apps/rails/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | 4 | # Rubocop supports only >=1.9.3 5 | gem 'rubocop', '~> 0.34', require: false unless RUBY_VERSION == '1.9.2' 6 | -------------------------------------------------------------------------------- /lib/airbrake/version.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # We use Semantic Versioning v2.0.0 3 | # More information: http://semver.org/ 4 | module Airbrake 5 | AIRBRAKE_VERSION = '5.1.0'.freeze 6 | end 7 | -------------------------------------------------------------------------------- /gemfiles/rack.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "warden", "~> 1.2.3" 7 | 8 | gemspec :path => "../" 9 | -------------------------------------------------------------------------------- /spec/apps/sinatra/dummy_app.rb: -------------------------------------------------------------------------------- 1 | class DummyApp < Sinatra::Base 2 | use Airbrake::Rack::Middleware 3 | use Warden::Manager 4 | 5 | get '/' do 6 | 'Hello from index' 7 | end 8 | 9 | get '/crash' do 10 | raise AirbrakeTestError 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /gemfiles/sinatra.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "sinatra", "~> 1.4.6" 7 | gem "rack-test", "~> 0.6.3" 8 | gem "warden", "~> 1.2.3" 9 | 10 | gemspec :path => "../" 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | log/* 2 | tmp 3 | db/schema.rb 4 | db/*.sqlite3 5 | public/system 6 | *.swp 7 | *.DS_Store 8 | coverage/* 9 | rdoc/ 10 | tags 11 | .yardoc 12 | doc 13 | pkg 14 | 15 | .bundle 16 | 17 | *.rbc 18 | *.plan 19 | gemfiles/*.lock 20 | .rbenv-version 21 | .rvmrc 22 | resources/notice.xml 23 | Gemfile.lock 24 | .#* 25 | *.log 26 | -------------------------------------------------------------------------------- /spec/apps/rack/dummy_app.rb: -------------------------------------------------------------------------------- 1 | DummyApp = Rack::Builder.new do 2 | use Rack::ShowExceptions 3 | use Airbrake::Rack::Middleware 4 | use Warden::Manager 5 | 6 | map '/' do 7 | run( 8 | proc do |_env| 9 | [200, { 'Content-Type' => 'text/plain' }, ['Hello from index']] 10 | end 11 | ) 12 | end 13 | 14 | map '/crash' do 15 | run proc { |_env| raise AirbrakeTestError } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | 3 | task default: 'spec:unit' 4 | 5 | namespace :spec do 6 | RSpec::Core::RakeTask.new(:unit) do |t| 7 | t.pattern = 'spec/unit/**/*_spec.rb' 8 | end 9 | 10 | namespace :integration do 11 | [:rails, :rack, :sinatra].each do |app| 12 | RSpec::Core::RakeTask.new(app) do |t| 13 | t.pattern = "spec/integration/#{app}/*_spec.rb" 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/integration/sinatra/sinatra_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/shared_examples/rack_examples' 3 | 4 | RSpec.describe "Sinatra integration specs" do 5 | let(:app) { DummyApp } 6 | 7 | include_examples 'rack examples' 8 | 9 | describe "context payload" do 10 | it "includes version" do 11 | get '/crash' 12 | wait_for_a_request_with_body(/"context":{.*"version":"1.2.3 Sinatra/) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/airbrake_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Airbrake do 4 | describe ".add_rack_builder" do 5 | let :builder do 6 | proc { |_, _| nil } 7 | end 8 | 9 | after { Airbrake::Rack::NoticeBuilder.builders.delete(builder) } 10 | 11 | it "adds new builder to the chain" do 12 | expect { Airbrake.add_rack_builder(&builder) }.to change { 13 | Airbrake::Rack::NoticeBuilder.builders.count 14 | }.by(1) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/integration/rack/rack_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/shared_examples/rack_examples' 3 | 4 | RSpec.describe "Rack integration specs" do 5 | let(:app) { DummyApp } 6 | 7 | include_examples 'rack examples' 8 | 9 | describe "context payload" do 10 | it "includes version" do 11 | get '/crash' 12 | wait_for_a_request_with_body( 13 | /"context":{.*"version":"1.2.3 Rack\.version.+Rack\.release/ 14 | ) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /gemfiles/rails_3.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "rails", "~> 3.2.22" 7 | gem "warden", "~> 1.2.3" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.18", :platforms => :jruby 9 | gem "sqlite3", "~> 1.3.11", :platforms => [:mri, :rbx] 10 | gem "resque", "~> 1.25.2" 11 | gem "resque_spec", :git => "git@github.com:kyrylo/resque_spec.git" 12 | gem "delayed_job_active_record", "~> 4.1.0" 13 | 14 | gemspec :path => "../" 15 | -------------------------------------------------------------------------------- /gemfiles/rails_4.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "rails", "~> 4.0.13" 7 | gem "warden", "~> 1.2.3" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.18", :platforms => :jruby 9 | gem "sqlite3", "~> 1.3.11", :platforms => [:mri, :rbx] 10 | gem "resque", "~> 1.25.2" 11 | gem "resque_spec", :git => "git@github.com:kyrylo/resque_spec.git" 12 | gem "delayed_job_active_record", "~> 4.1.0" 13 | 14 | gemspec :path => "../" 15 | -------------------------------------------------------------------------------- /gemfiles/rails_4.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "rails", "~> 4.1.13" 7 | gem "warden", "~> 1.2.3" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.18", :platforms => :jruby 9 | gem "sqlite3", "~> 1.3.11", :platforms => [:mri, :rbx] 10 | gem "resque", "~> 1.25.2" 11 | gem "resque_spec", :git => "git@github.com:kyrylo/resque_spec.git" 12 | gem "delayed_job_active_record", "~> 4.1.0" 13 | 14 | gemspec :path => "../" 15 | -------------------------------------------------------------------------------- /gemfiles/rails_4.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "rails", "~> 4.2.4" 7 | gem "warden", "~> 1.2.3" 8 | gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.18", :platforms => :jruby 9 | gem "sqlite3", "~> 1.3.11", :platforms => [:mri, :rbx] 10 | gem "resque", "~> 1.25.2" 11 | gem "resque_spec", :git => "git@github.com:kyrylo/resque_spec.git" 12 | gem "delayed_job_active_record", "~> 4.1.0" 13 | 14 | gemspec :path => "../" 15 | -------------------------------------------------------------------------------- /lib/airbrake/resque/failure.rb: -------------------------------------------------------------------------------- 1 | require 'resque/failure/base' 2 | 3 | module Resque 4 | module Failure 5 | ## 6 | # Provides Resque integration with Airbrake. 7 | # 8 | # @since v5.0.0 9 | # @see https://github.com/resque/resque/wiki/Failure-Backends 10 | class Airbrake < Base 11 | def save 12 | params = payload.merge( 13 | component: 'resque', 14 | action: payload['class'].to_s 15 | ) 16 | 17 | ::Airbrake.notify_sync(exception, params) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /gemfiles/rails_edge.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "rubocop", "~> 0.34", :require => false 6 | gem "rails", :github => "rails/rails" 7 | gem "arel", :github => "rails/arel" 8 | gem "rack", :github => "rack/rack" 9 | gem "warden", "~> 1.2.3" 10 | gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.18", :platforms => :jruby 11 | gem "sqlite3", "~> 1.3.11", :platforms => [:mri, :rbx] 12 | gem "resque", "~> 1.25.2" 13 | gem "resque_spec", :git => "git@github.com:kyrylo/resque_spec.git" 14 | gem "delayed_job_active_record", "~> 4.1.0" 15 | 16 | gemspec :path => "../" 17 | -------------------------------------------------------------------------------- /spec/apps/rails/dummy_task.rake: -------------------------------------------------------------------------------- 1 | # Keep this before any task definitions to collect extra info about tasks. 2 | # Without this line the tests will fail. 3 | Rake::TaskManager.record_task_metadata = true 4 | 5 | namespace :bingo do 6 | # This task contains *maximum* amount of information. 7 | desc 'Dummy description' 8 | task :bango, [:dummy_arg] => [:environment] do |_t, _args| 9 | raise AirbrakeTestError 10 | end 11 | 12 | # This task contains *minimum* amount of information. 13 | task :bongo do 14 | raise AirbrakeTestError 15 | end 16 | 17 | task :environment do 18 | # No-op. 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/airbrake/rails/active_job.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rails 3 | ## 4 | # Enables support for exceptions occurring in ActiveJob jobs. 5 | module ActiveJob 6 | extend ActiveSupport::Concern 7 | 8 | included do 9 | rescue_from(Exception) do |exception| 10 | notice = Airbrake.build_notice(exception) 11 | 12 | notice[:context][:component] = self.class.name 13 | notice[:context][:action] = job_id 14 | 15 | notice[:params] = as_json 16 | 17 | Airbrake.notify(notice) 18 | raise exception 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/generators/airbrake_generator.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Creates the Airbrake initializer file for Rails apps. 3 | # 4 | # @example Invokation from terminal 5 | # rails generate airbrake PROJECT_KEY PROJECT_ID [NAME] 6 | # 7 | class AirbrakeGenerator < Rails::Generators::Base 8 | # Adds current directory to source paths, so we can find the template file. 9 | source_root File.expand_path('..', __FILE__) 10 | 11 | argument :project_id, required: false 12 | argument :project_key, required: false 13 | 14 | ## 15 | # Makes the NAME option optional, which allows to subclass from Base, so we 16 | # can pass arguments to the ERB template. 17 | # 18 | # @see http://asciicasts.com/episodes/218-making-generators-in-rails-3 19 | argument :name, type: :string, default: 'application' 20 | 21 | desc 'Configures the Airbrake notifier with your project id and project key' 22 | def generate_layout 23 | template 'airbrake_initializer.rb.erb', 'config/initializers/airbrake.rb' 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/airbrake/sidekiq/error_handler.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Sidekiq 3 | ## 4 | # Provides integration with Sidekiq 2 and Sidekiq 3. 5 | class ErrorHandler 6 | # rubocop:disable Lint/RescueException 7 | def call(_worker, context, _queue) 8 | yield 9 | rescue Exception => exception 10 | notify_airbrake(exception, context) 11 | raise exception 12 | end 13 | # rubocop:enable Lint/RescueException 14 | 15 | private 16 | 17 | def notify_airbrake(exception, context) 18 | params = context.merge(component: 'sidekiq', action: context['class']) 19 | Airbrake.notify(exception, params) 20 | end 21 | end 22 | end 23 | end 24 | 25 | if Sidekiq::VERSION < '3' 26 | Sidekiq.configure_server do |config| 27 | config.server_middleware do |chain| 28 | chain.add(Airbrake::Sidekiq::ErrorHandler) 29 | end 30 | end 31 | else 32 | Sidekiq.configure_server do |config| 33 | config.error_handlers << Airbrake::Sidekiq::ErrorHandler.new.method(:notify_airbrake) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/unit/sidekiq/error_handler_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0') 4 | RSpec.describe "airbrake/sidekiq/error_handler" do 5 | let(:endpoint) do 6 | 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822' 7 | end 8 | 9 | def wait_for_a_request_with_body(body) 10 | wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once 11 | end 12 | 13 | before do 14 | stub_request(:post, endpoint).to_return(status: 201, body: '{}') 15 | end 16 | 17 | it "sends a notice to Airbrake" do 18 | handler = Sidekiq.error_handlers.last 19 | handler.call( 20 | AirbrakeTestError.new('sidekiq error'), 21 | 'class' => 'HardSidekiqWorker', 'args' => %w(bango bongo) 22 | ) 23 | 24 | wait_for_a_request_with_body(/"message":"sidekiq\serror"/) 25 | wait_for_a_request_with_body(/"params":{.*"args":\["bango","bongo"\]/) 26 | wait_for_a_request_with_body(/"component":"sidekiq","action":"HardSidekiqWorker"/) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | =============== 3 | 4 | Copyright © 2015 Airbrake Technologies, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the 'Software'), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /spec/unit/rake/tasks_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "airbrake/rake/tasks" do 4 | let(:endpoint) do 5 | 'https://airbrake.io/api/v4/projects/113743/deploys?key=fd04e13d806a90f96614ad8e529b2822' 6 | end 7 | 8 | def wait_for_a_request_with_body(body) 9 | wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once 10 | end 11 | 12 | before do 13 | stub_request(:post, endpoint).to_return(status: 201, body: '{}') 14 | end 15 | 16 | describe "airbrake:deploy" do 17 | let(:task) { Rake::Task['airbrake:deploy'] } 18 | 19 | after { task.reenable } 20 | 21 | shared_examples 'deploy payload' do |key, val| 22 | it "sends #{key}" do 23 | ENV[key.upcase] = val 24 | task.invoke 25 | 26 | wait_for_a_request_with_body(/{.*"#{key}":"#{val}".*}/) 27 | ENV[key.upcase] = nil 28 | end 29 | end 30 | 31 | [%w(environment production), 32 | %w(username john), 33 | %w(revision 123abcdef), 34 | %w(repository https://github.com/airbrake/airbrake'), 35 | %w(version v2.0) 36 | ].each do |(key, val)| 37 | include_examples 'deploy payload', key, val 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/airbrake/rails/action_controller.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rails 3 | ## 4 | # Contains helper methods that can be used inside Rails controllers to send 5 | # notices to Airbrake. The main benefit of using them instead of the direct 6 | # API is that they automatically add information from the Rack environment 7 | # to notices. 8 | module ActionController 9 | private 10 | 11 | ## 12 | # A helper method for sending notices to Airbrake *asynchronously*. 13 | # Attaches information from the Rack env. 14 | # @see Airbrake#notify, #notify_airbrake_sync 15 | def notify_airbrake(exception, parameters = {}, notifier = :default) 16 | Airbrake.notify(build_notice(exception), parameters, notifier) 17 | end 18 | 19 | ## 20 | # A helper method for sending notices to Airbrake *synchronously*. 21 | # Attaches information from the Rack env. 22 | # @see Airbrake#notify_sync, #notify_airbrake 23 | def notify_airbrake_sync(exception, parameters = {}, notifier = :default) 24 | Airbrake.notify_sync(build_notice(exception), parameters, notifier) 25 | end 26 | 27 | ## 28 | # @param [Exception] exception 29 | # @return [Airbrake::Notice] the notice with information from the Rack env 30 | def build_notice(exception) 31 | Airbrake::Rack::NoticeBuilder.new(request.env).build_notice(exception) 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/airbrake/rails/active_record.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rails 3 | ## 4 | # Rails <4.2 has a bug with regard to swallowing exceptions in the 5 | # +after_commit+ and the +after_rollback+ hooks: it doesn't bubble up 6 | # exceptions from there. 7 | # 8 | # This module makes it possible to report exceptions occurring there. 9 | # 10 | # @see https://github.com/rails/rails/pull/14488 Detailed description of the 11 | # bug and the fix 12 | # @see https://goo.gl/348lor Rails 4.2+ implementation (fixed) 13 | # @see https://goo.gl/ddFNg7 Rails <4.2 implementation (bugged) 14 | module ActiveRecord 15 | ## 16 | # @return [Array] the hooks that needs fixing 17 | KINDS = [:commit, :rollback].freeze 18 | 19 | ## 20 | # Patches default +run_callbacks+ with our version, which is capable of 21 | # notifying about exceptions. 22 | # 23 | # rubocop:disable Lint/RescueException 24 | def run_callbacks(kind, *args, &block) 25 | # Let the post process handle the exception if it's not a bugged hook. 26 | return super unless KINDS.include?(kind) 27 | 28 | # Handle the exception ourselves. The 'ex' exception won't be 29 | # propagated, therefore we must notify it here. 30 | begin 31 | super 32 | rescue Exception => ex 33 | Airbrake.notify(ex) 34 | raise ex 35 | end 36 | end 37 | # rubocop:enable Lint/RescueException 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # Explanations of all possible options: 2 | # https://github.com/bbatsov/rubocop/blob/master/config/default.yml 3 | AllCops: 4 | DisplayCopNames: true 5 | DisplayStyleGuide: true 6 | 7 | Lint/HandleExceptions: 8 | Enabled: true 9 | 10 | Metrics/MethodLength: 11 | Max: 25 12 | 13 | Style/SpaceInsideBrackets: 14 | Enabled: true 15 | 16 | Metrics/LineLength: 17 | Max: 90 18 | 19 | Style/AccessorMethodName: 20 | Enabled: true 21 | 22 | Style/DotPosition: 23 | EnforcedStyle: trailing 24 | 25 | # Details: 26 | # http://c2.com/cgi/wiki?AbcMetric 27 | Metrics/AbcSize: 28 | # The ABC size is a calculated magnitude, so this number can be a Fixnum or 29 | # a Float. 30 | Max: 20 31 | 32 | Style/StringLiterals: 33 | Enabled: false 34 | 35 | Style/HashSyntax: 36 | EnforcedStyle: ruby19 37 | 38 | Style/GuardClause: 39 | Enabled: true 40 | 41 | Style/SpaceInsideHashLiteralBraces: 42 | Enabled: true 43 | 44 | Style/NumericLiterals: 45 | Enabled: false 46 | 47 | Style/ParallelAssignment: 48 | Enabled: true 49 | 50 | Style/SpaceAroundOperators: 51 | Enabled: true 52 | 53 | Style/SignalException: 54 | EnforcedStyle: only_raise 55 | 56 | Style/RedundantSelf: 57 | Enabled: true 58 | 59 | Style/SpaceInsideParens: 60 | Enabled: true 61 | 62 | # TODO: enable this when Ruby 3.0 is out. 63 | Style/FrozenStringLiteralComment: 64 | Enabled: false 65 | 66 | Style/ConditionalAssignment: 67 | Enabled: true 68 | 69 | Performance/StartWith: 70 | Enabled: true 71 | 72 | Style/Alias: 73 | Enabled: true 74 | -------------------------------------------------------------------------------- /lib/airbrake/delayed_job/plugin.rb: -------------------------------------------------------------------------------- 1 | module Delayed 2 | module Plugins 3 | ## 4 | # Provides integration with Delayed Job. 5 | # rubocop:disable Lint/RescueException 6 | class Airbrake < ::Delayed::Plugin 7 | callbacks do |lifecycle| 8 | lifecycle.around(:invoke_job) do |job, *args, &block| 9 | begin 10 | # Forward the call to the next callback in the callback chain 11 | block.call(job, *args) 12 | rescue Exception => exception 13 | params = job.as_json.merge( 14 | component: 'delayed_job', 15 | action: job.payload_object.class.name 16 | ) 17 | 18 | # If DelayedJob is used through ActiveJob, it contains extra info. 19 | if job.payload_object.respond_to?(:job_data) 20 | params[:active_job] = job.payload_object.job_data 21 | end 22 | 23 | ::Airbrake.notify(exception, params) 24 | raise exception 25 | end 26 | end 27 | end 28 | end 29 | # rubocop:enable Lint/RescueException 30 | end 31 | end 32 | 33 | if RUBY_ENGINE == 'jruby' && defined?(Delayed::Backend::ActiveRecord::Job) 34 | ## 35 | # Workaround against JRuby bug: 36 | # https://github.com/jruby/jruby/issues/3338 37 | # rubocop:disable Style/ClassAndModuleChildren 38 | class Delayed::Backend::ActiveRecord::Job 39 | alias old_to_ary to_ary 40 | 41 | def to_ary 42 | old_to_ary || [self] 43 | end 44 | end 45 | # rubocop:enable Style/ClassAndModuleChildren 46 | end 47 | 48 | Delayed::Worker.plugins << Delayed::Plugins::Airbrake 49 | -------------------------------------------------------------------------------- /lib/airbrake.rb: -------------------------------------------------------------------------------- 1 | require 'shellwords' 2 | 3 | # Core library that sends notices. 4 | # See: https://github.com/airbrake/airbrake-ruby 5 | require 'airbrake-ruby' 6 | 7 | require 'airbrake/version' 8 | 9 | # Automatically load needed files for the environment the library is running in. 10 | if defined?(Rack) 11 | require 'airbrake/rack/user' 12 | require 'airbrake/rack/notice_builder' 13 | require 'airbrake/rack/middleware' 14 | 15 | require 'airbrake/rails/railtie' if defined?(Rails) 16 | end 17 | 18 | require 'airbrake/rake/task_ext' if defined?(Rake::Task) 19 | require 'airbrake/resque/failure' if defined?(Resque) 20 | require 'airbrake/sidekiq/error_handler' if defined?(Sidekiq) 21 | require 'airbrake/delayed_job/plugin' if defined?(Delayed) 22 | 23 | ## 24 | # This module reopens the original Airbrake module from airbrake-ruby and adds 25 | # integration specific methods. 26 | module Airbrake 27 | class << self 28 | ## 29 | # Attaches a callback (builder) that runs every time the Rack integration 30 | # reports an error. Can be used to attach additional data from the Rack 31 | # request. 32 | # 33 | # @example Adding remote IP from the Rack environment 34 | # Airbrake.add_rack_builder do |notice, request| 35 | # notice[:params][:remoteIp] = request.env['REMOTE_IP'] 36 | # end 37 | # 38 | # @yieldparam notice [Airbrake::Notice] notice that will be sent to Airbrake 39 | # @yieldparam request [Rack::Request] current rack request 40 | # @yieldreturn [void] 41 | # @return [void] 42 | # @since 5.1.0 43 | def add_rack_builder(&block) 44 | Airbrake::Rack::NoticeBuilder.add_builder(&block) 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /airbrake.gemspec: -------------------------------------------------------------------------------- 1 | require './lib/airbrake/version' 2 | 3 | Gem::Specification.new do |s| 4 | s.name = 'airbrake' 5 | s.version = Airbrake::AIRBRAKE_VERSION.dup 6 | s.date = Time.now.strftime('%Y-%m-%d') 7 | s.summary = < 1.1' 33 | 34 | s.add_development_dependency 'rspec', '~> 3' 35 | s.add_development_dependency 'rspec-wait', '~> 0' 36 | s.add_development_dependency 'rake', '~> 10' 37 | s.add_development_dependency 'pry', '~> 0' 38 | s.add_development_dependency 'appraisal', '~> 2' 39 | s.add_development_dependency 'rack', '~> 1' 40 | s.add_development_dependency 'webmock', '~> 1' 41 | s.add_development_dependency 'rack-test', '~> 0' 42 | s.add_development_dependency 'sidekiq', '~> 4' 43 | end 44 | -------------------------------------------------------------------------------- /lib/airbrake/rack/user.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rack 3 | ## 4 | # Represents an authenticated user, which can be converted to Airbrake's 5 | # payload format. Supports Warden and Omniauth authentication frameworks. 6 | class User 7 | # Finds the user in the Rack environment and creates a new user wrapper. 8 | # 9 | # @param [Hash{String=>Object}] rack_env The Rack environment 10 | # @return [Airbrake::Rack::User, nil] 11 | def self.extract(rack_env) 12 | # Warden support (including Devise). 13 | if (warden = rack_env['warden']) 14 | if (user = warden.user(run_callbacks: false)) 15 | return new(user) if user 16 | end 17 | end 18 | 19 | # Fallback mode (OmniAuth support included). Works only for Rails. 20 | controller = rack_env['action_controller.instance'] 21 | return unless controller.respond_to?(:current_user) 22 | new(controller.current_user) if controller.current_user 23 | end 24 | 25 | def initialize(user) 26 | @user = user 27 | end 28 | 29 | def as_json 30 | user = {} 31 | 32 | user[:id] = try_to_get(:id) 33 | user[:name] = full_name 34 | user[:username] = try_to_get(:username) 35 | user[:email] = try_to_get(:email) 36 | 37 | user = user.delete_if { |_key, val| val.nil? } 38 | user.empty? ? user : { user: user } 39 | end 40 | 41 | private 42 | 43 | def try_to_get(key) 44 | String(@user.__send__(key)) if @user.respond_to?(key) 45 | end 46 | 47 | def full_name 48 | # Try to get first and last names. If that fails, try to get just 'name'. 49 | name = [try_to_get(:first_name), try_to_get(:last_name)].compact.join(' ') 50 | name.empty? ? try_to_get(:name) : name 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/airbrake/rack/middleware.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rack 3 | ## 4 | # Airbrake Rack middleware for Rails and Sinatra applications (or any other 5 | # Rack-compliant app). Any errors raised by the upstream application will be 6 | # delivered to Airbrake and re-raised. 7 | # 8 | # The middleware automatically sends information about the framework that 9 | # uses it (name and version). 10 | class Middleware 11 | def initialize(app) 12 | @app = app 13 | end 14 | 15 | ## 16 | # Rescues any exceptions, sends them to Airbrake and re-raises the 17 | # exception. 18 | # @param [Hash] env the Rack environment 19 | def call(env) 20 | # rubocop:disable Lint/RescueException 21 | begin 22 | response = @app.call(env) 23 | rescue Exception => ex 24 | notify_airbrake(ex, env) 25 | raise ex 26 | end 27 | # rubocop:enable Lint/RescueException 28 | 29 | exception = framework_exception(env) 30 | notify_airbrake(exception, env) if exception 31 | 32 | response 33 | end 34 | 35 | private 36 | 37 | def notify_airbrake(exception, env) 38 | notice = NoticeBuilder.new(env).build_notice(exception) 39 | Airbrake.notify(notice) 40 | end 41 | 42 | ## 43 | # Web framework middlewares often store rescued exceptions inside the 44 | # Rack env, but Rack doesn't have a standard key for it: 45 | # 46 | # - Rails uses action_dispatch.exception: https://goo.gl/Kd694n 47 | # - Sinatra uses sinatra.error: https://goo.gl/LLkVL9 48 | # - Goliath uses rack.exception: https://goo.gl/i7e1nA 49 | def framework_exception(env) 50 | env['action_dispatch.exception'] || 51 | env['sinatra.error'] || 52 | env['rack.exception'] 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/airbrake/rake/task_ext.rb: -------------------------------------------------------------------------------- 1 | # This is not bulletproof, but if this file is executed before a task 2 | # definition, we can grab tasks descriptions and locations. 3 | # See: https://goo.gl/ksn6PE 4 | Rake::TaskManager.record_task_metadata = true 5 | 6 | module Rake 7 | ## 8 | # Redefine +Rake::Task#execute+, so it can report errors to Airbrake. 9 | class Task 10 | # Store the original method to use it later. 11 | alias execute_without_airbrake execute 12 | 13 | ## 14 | # A wrapper around the original +#execute+, that catches all errors and 15 | # notifies Airbrake. 16 | # 17 | # rubocop:disable Lint/RescueException 18 | def execute(args = nil) 19 | execute_without_airbrake(args) 20 | rescue Exception => ex 21 | notice = Airbrake.build_notice(ex) 22 | notice[:context][:component] = 'rake' 23 | notice[:context][:action] = name 24 | notice[:params] = { 25 | rake_task: task_info, 26 | execute_args: args, 27 | argv: ARGV.join(' ') 28 | } 29 | 30 | Airbrake.notify_sync(notice) 31 | raise ex 32 | end 33 | # rubocop:enable Lint/RescueException 34 | 35 | private 36 | 37 | # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize 38 | def task_info 39 | info = {} 40 | 41 | info[:name] = name 42 | info[:timestamp] = timestamp.to_s 43 | info[:investigation] = investigation 44 | 45 | info[:full_comment] = full_comment if full_comment 46 | info[:arg_names] = arg_names if arg_names.any? 47 | info[:arg_description] = arg_description if arg_description 48 | info[:locations] = locations if locations.any? 49 | info[:sources] = sources if sources.any? 50 | 51 | if prerequisite_tasks.any? 52 | info[:prerequisite_tasks] = prerequisite_tasks.map do |p| 53 | p.__send__(:task_info) 54 | end 55 | end 56 | 57 | info 58 | end 59 | # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to contribute 2 | ================= 3 | 4 | Pull requests 5 | ------------- 6 | 7 | 8 | 9 | We love your contributions, thanks for taking the time to contribute! 10 | 11 | It's really easy to start contributing, just follow these simple steps: 12 | 13 | 1. [Fork][fork-article] the [repo][airbrake]: 14 | 15 | ![Fork][fork] 16 | 17 | 2. Run the test suite to make sure the tests pass: 18 | 19 | ```shell 20 | bundle exec rake 21 | ``` 22 | 23 | 3. [Create a separate branch][branch], commit your work and push it to your 24 | fork. If you add comments, please make sure that they are compatible with 25 | [YARD][yard]: 26 | 27 | ``` 28 | git checkout -b my-branch 29 | git commit -am 30 | git push origin my-branch 31 | ``` 32 | 33 | 4. Verify that your code doesn't offend Rubocop: 34 | 35 | ``` 36 | bundle exec rubocop 37 | ``` 38 | 39 | 5. Run the test suite again (new tests are always welcome): 40 | 41 | ``` 42 | bundle exec rake 43 | ``` 44 | 45 | 6. [Make a pull request][pr] 46 | 47 | Submitting issues 48 | ----------------- 49 | 50 | Our [issue tracker][issues] is a perfect place for filing bug reports or 51 | discussing possible features. If you report a bug, consider using the following 52 | template (copy-paste friendly): 53 | 54 | ``` 55 | * Airbrake version: {YOUR VERSION} 56 | * Ruby version: {YOUR VERSION} 57 | * Framework name & version: {YOUR DATA} 58 | 59 | #### Airbrake config 60 | 61 | # YOUR CONFIG 62 | # 63 | # Make sure to delete any sensitive information 64 | # such as your project id and project key. 65 | 66 | #### Description 67 | 68 | {We would be thankful if you provided steps to reproduce the issue, expected & 69 | actual results, any code snippets or even test repositories, so we could clone 70 | it and test} 71 | ``` 72 | 73 |

74 | 75 | Build Better Software 76 |

77 | 78 | [airbrake]: https://github.com/airbrake/airbrake 79 | [fork-article]: https://help.github.com/articles/fork-a-repo 80 | [fork]: https://img-fotki.yandex.ru/get/3800/98991937.1f/0_b5c39_839c8786_orig 81 | [branch]: https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/ 82 | [pr]: https://help.github.com/articles/using-pull-requests 83 | [issues]: https://github.com/airbrake/airbrake/issues 84 | [yard]: http://yardoc.org/ 85 | -------------------------------------------------------------------------------- /lib/airbrake/rails/railtie.rb: -------------------------------------------------------------------------------- 1 | module Airbrake 2 | module Rails 3 | ## 4 | # This railtie works for any Rails application that supports railties (Rails 5 | # 3.2+ apps). It makes Airbrake Ruby work with Rails and report errors 6 | # occurring in the application automatically. 7 | class Railtie < ::Rails::Railtie 8 | initializer('airbrake.middleware') do |app| 9 | # Since Rails 3.2 the ActionDispatch::DebugExceptions middleware is 10 | # responsible for logging exceptions and showing a debugging page in 11 | # case the request is local. We want to insert our middleware after 12 | # DebugExceptions, so we don't notify Airbrake about local requests. 13 | 14 | if ::Rails.version.start_with?('5.') 15 | # Avoid the warning about deprecated strings. 16 | app.config.middleware.insert_after( 17 | ActionDispatch::DebugExceptions, Airbrake::Rack::Middleware 18 | ) 19 | else 20 | app.config.middleware.insert_after( 21 | ActionDispatch::DebugExceptions, 'Airbrake::Rack::Middleware' 22 | ) 23 | end 24 | end 25 | 26 | rake_tasks do 27 | # Report exceptions occurring in Rake tasks. 28 | require 'airbrake/rake/task_ext' 29 | 30 | # Defines tasks such as `airbrake:test` & `airbrake:deploy`. 31 | require 'airbrake/rake/tasks' 32 | end 33 | 34 | initializer('airbrake.action_controller') do 35 | ActiveSupport.on_load(:action_controller) do 36 | # Patches ActionController with methods that allow us to retrieve 37 | # interesting request data. Appends that information to notices. 38 | require 'airbrake/rails/action_controller' 39 | include Airbrake::Rails::ActionController 40 | end 41 | end 42 | 43 | initializer('airbrake.active_record') do 44 | ActiveSupport.on_load(:active_record) do 45 | # Reports exceptions occurring in some bugged ActiveRecord callbacks. 46 | # Applicable only to the versions of Rails lower than 4.2. 47 | require 'airbrake/rails/active_record' 48 | include Airbrake::Rails::ActiveRecord 49 | end 50 | end 51 | 52 | initializer('airbrake.active_job') do 53 | ActiveSupport.on_load(:active_job) do 54 | # Reports exceptions occurring in ActiveJob jobs. 55 | require 'airbrake/rails/active_job' 56 | include Airbrake::Rails::ActiveJob 57 | end 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/airbrake/capistrano/tasks.rb: -------------------------------------------------------------------------------- 1 | if defined?(Capistrano::VERSION) && 2 | Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0') 3 | namespace :airbrake do 4 | desc "Notify Airbrake of the deploy" 5 | task :deploy do 6 | role = roles(:all, select: :primary).first || roles(:all).first 7 | on role do 8 | within release_path do 9 | with rails_env: fetch(:rails_env, fetch(:stage)) do 10 | execute :rake, <<-CMD 11 | airbrake:deploy USERNAME=#{Shellwords.shellescape(local_user)} \ 12 | ENVIRONMENT=#{fetch(:airbrake_env, fetch(:rails_env, fetch(:stage)))} \ 13 | REVISION=#{fetch(:current_revision)} \ 14 | REPOSITORY=#{fetch(:repo_url)} \ 15 | VERSION=#{fetch(:app_version)} 16 | CMD 17 | 18 | info 'Notified Airbrake of the deploy' 19 | end 20 | end 21 | end 22 | end 23 | end 24 | else 25 | module Airbrake 26 | ## 27 | # The Capistrano v2 integration. 28 | module Capistrano 29 | # rubocop:disable Metrics/AbcSize 30 | def self.load_into(config) 31 | config.load do 32 | after 'deploy', 'airbrake:deploy' 33 | after 'deploy:migrations', 'airbrake:deploy' 34 | after 'deploy:cold', 'airbrake:deploy' 35 | 36 | namespace :airbrake do 37 | desc "Notify Airbrake of the deploy" 38 | task :deploy, except: { no_release: true }, on_error: :continue do 39 | username = Shellwords.shellescape(ENV['USER'] || ENV['USERNAME']) 40 | command = <<-CMD 41 | cd #{config.release_path} && \ 42 | 43 | RACK_ENV=#{fetch(:rack_env, nil)} \ 44 | RAILS_ENV=#{fetch(:rails_env, nil)} \ 45 | 46 | bundle exec rake airbrake:deploy \ 47 | USERNAME=#{username} \ 48 | ENVIRONMENT=#{fetch(:rails_env, 'production')} \ 49 | REVISION=#{current_revision.strip} \ 50 | REPOSITORY=#{repository} \ 51 | VERSION=#{fetch(:app_version, nil)} 52 | CMD 53 | 54 | run(command, once: true) 55 | logger.info 'Notified Airbrake of the deploy' 56 | end 57 | end 58 | end 59 | end 60 | # rubocop:enable Metrics/AbcSize 61 | end 62 | end 63 | 64 | Airbrake::Capistrano.load_into(Capistrano::Configuration.instance) 65 | end 66 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise 'rails-3.2' do 2 | gem 'rails', '~> 3.2.22' 3 | gem 'warden', '~> 1.2.3' 4 | 5 | gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.18', platforms: :jruby 6 | gem 'sqlite3', '~> 1.3.11', platforms: [:mri, :rbx] 7 | 8 | gem 'resque', '~> 1.25.2' 9 | gem 'resque_spec', git: 'git@github.com:kyrylo/resque_spec.git' 10 | 11 | gem 'delayed_job_active_record', '~> 4.1.0' 12 | end 13 | 14 | appraise 'rails-4.0' do 15 | gem 'rails', '~> 4.0.13' 16 | gem 'warden', '~> 1.2.3' 17 | 18 | gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.18', platforms: :jruby 19 | gem 'sqlite3', '~> 1.3.11', platforms: [:mri, :rbx] 20 | 21 | gem 'resque', '~> 1.25.2' 22 | gem 'resque_spec', git: 'git@github.com:kyrylo/resque_spec.git' 23 | 24 | gem 'delayed_job_active_record', '~> 4.1.0' 25 | end 26 | 27 | appraise 'rails-4.1' do 28 | gem 'rails', '~> 4.1.13' 29 | gem 'warden', '~> 1.2.3' 30 | 31 | gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.18', platforms: :jruby 32 | gem 'sqlite3', '~> 1.3.11', platforms: [:mri, :rbx] 33 | 34 | gem 'resque', '~> 1.25.2' 35 | gem 'resque_spec', git: 'git@github.com:kyrylo/resque_spec.git' 36 | 37 | gem 'delayed_job_active_record', '~> 4.1.0' 38 | end 39 | 40 | appraise 'rails-4.2' do 41 | gem 'rails', '~> 4.2.4' 42 | gem 'warden', '~> 1.2.3' 43 | 44 | gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.18', platforms: :jruby 45 | gem 'sqlite3', '~> 1.3.11', platforms: [:mri, :rbx] 46 | 47 | gem 'resque', '~> 1.25.2' 48 | gem 'resque_spec', git: 'git@github.com:kyrylo/resque_spec.git' 49 | 50 | gem 'delayed_job_active_record', '~> 4.1.0' 51 | end 52 | 53 | # Rails 5+ supports only Ruby 2.1+ 54 | if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0') 55 | appraise 'rails-edge' do 56 | gem 'rails', github: 'rails/rails' 57 | gem 'arel', github: 'rails/arel' 58 | gem 'rack', github: 'rack/rack' 59 | gem 'warden', '~> 1.2.3' 60 | 61 | gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.18', platforms: :jruby 62 | gem 'sqlite3', '~> 1.3.11', platforms: [:mri, :rbx] 63 | 64 | gem 'resque', '~> 1.25.2' 65 | # A temporary fork of https://github.com/leshill/resque_spec with 66 | # https://github.com/leshill/resque_spec/pull/88 merged in. This allows us 67 | # to test our Resque integration. 68 | gem 'resque_spec', git: 'git@github.com:kyrylo/resque_spec.git' 69 | 70 | gem 'delayed_job_active_record', '~> 4.1.0' 71 | end 72 | end 73 | 74 | appraise 'sinatra' do 75 | gem 'sinatra', '~> 1.4.6' 76 | gem 'rack-test', '~> 0.6.3' 77 | gem 'warden', '~> 1.2.3' 78 | end 79 | 80 | appraise 'rack' do 81 | gem 'warden', '~> 1.2.3' 82 | end 83 | -------------------------------------------------------------------------------- /spec/unit/rack/middleware_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Airbrake::Rack::Middleware do 4 | let(:app) do 5 | proc { |env| [200, env, 'Bingo bango content'] } 6 | end 7 | 8 | let(:faulty_app) do 9 | proc { raise AirbrakeTestError } 10 | end 11 | 12 | let(:endpoint) do 13 | 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822' 14 | end 15 | 16 | let(:middleware) { described_class.new(app) } 17 | 18 | def env_for(url, opts = {}) 19 | Rack::MockRequest.env_for(url, opts) 20 | end 21 | 22 | def wait_for_a_request_with_body(body) 23 | wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once 24 | end 25 | 26 | before do 27 | stub_request(:post, endpoint).to_return(status: 201, body: '{}') 28 | end 29 | 30 | describe "#call" do 31 | context "when app raises an exception" do 32 | it "rescues the exception, notifies Airbrake & re-raises it" do 33 | expect { described_class.new(faulty_app).call(env_for('/')) }. 34 | to raise_error(AirbrakeTestError) 35 | 36 | wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/) 37 | end 38 | 39 | it "sends framework version and name" do 40 | expect { described_class.new(faulty_app).call(env_for('/bingo/bango')) }. 41 | to raise_error(AirbrakeTestError) 42 | 43 | wait_for_a_request_with_body( 44 | %r("context":{.*"version":"1.2.3 (Rails|Sinatra|Rack\.version)/.+".+}) 45 | ) 46 | end 47 | end 48 | 49 | context "when app doesn't raise" do 50 | context "and previous middleware stored an exception in env" do 51 | shared_examples 'stored exception' do |type| 52 | it "notifies on #{type}, but doesn't raise" do 53 | env = env_for('/').merge(type => AirbrakeTestError.new) 54 | described_class.new(app).call(env) 55 | 56 | wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/) 57 | end 58 | end 59 | 60 | ['rack.exception', 'action_dispatch.exception', 'sinatra.error'].each do |type| 61 | include_examples 'stored exception', type 62 | end 63 | end 64 | 65 | it "doesn't notify Airbrake" do 66 | described_class.new(app).call(env_for('/')) 67 | sleep 1 68 | expect(a_request(:post, endpoint)).not_to have_been_made 69 | end 70 | end 71 | 72 | it "returns a response" do 73 | response = described_class.new(app).call(env_for('/')) 74 | 75 | expect(response[0]).to eq(200) 76 | expect(response[1]).to be_a(Hash) 77 | expect(response[2]).to eq('Bingo bango content') 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/generators/airbrake_initializer.rb.erb: -------------------------------------------------------------------------------- 1 | # Airbrake is an online tool that provides robust exception tracking in your Rails 2 | # applications. In doing so, it allows you to easily review errors, tie an error 3 | # to an individual piece of code, and trace the cause back to recent 4 | # changes. Airbrake enables for easy categorization, searching, and prioritization 5 | # of exceptions so that when errors occur, your team can quickly determine the 6 | # root cause. 7 | # 8 | # Configuration details: 9 | # https://github.com/airbrake/airbrake-ruby#configuration 10 | Airbrake.configure do |c| 11 | # You must set both project_id & project_key. To find your project_id and 12 | # project_key navigate to your project's General Settings and copy the values 13 | # from the right sidebar. 14 | # https://github.com/airbrake/airbrake-ruby#project_id--project_key 15 | <% if project_id -%> 16 | c.project_id = <%= project_id %> 17 | <% else -%> 18 | c.project_id = ENV['AIRBRAKE_PROJECT_ID'] 19 | <% end -%> 20 | <% if project_key -%> 21 | c.project_key = '<%= project_key %>' 22 | <% else -%> 23 | c.project_key = ENV['AIRBRAKE_API_KEY'] 24 | <% end -%> 25 | 26 | # Configures the root directory of your project. Expects a String or a 27 | # Pathname, which represents the path to your project. Providing this option 28 | # helps us to filter out repetitive data from backtrace frames and link to 29 | # GitHub files from our dashboard. 30 | # https://github.com/airbrake/airbrake-ruby#root_directory 31 | c.root_directory = Rails.root 32 | 33 | # By default, Airbrake Ruby outputs to STDOUT. In Rails apps it makes sense to 34 | # use the Rails' logger. 35 | # https://github.com/airbrake/airbrake-ruby#logger 36 | c.logger = Rails.logger 37 | 38 | # Configures the environment the application is running in. Helps the Airbrake 39 | # dashboard to distinguish between exceptions occurring in different 40 | # environments. By default, it's not set. 41 | # NOTE: This option must be set in order to make the 'ignore_environments' 42 | # option work. 43 | # https://github.com/airbrake/airbrake-ruby#environment 44 | c.environment = Rails.env 45 | 46 | # Setting this option allows Airbrake to filter exceptions occurring in 47 | # unwanted environments such as :test. By default, it is equal to an empty 48 | # Array, which means Airbrake Ruby sends exceptions occurring in all 49 | # environments. 50 | # NOTE: This option *does not* work if you don't set the 'environment' option. 51 | # https://github.com/airbrake/airbrake-ruby#ignore_environments 52 | c.ignore_environments = %w(test) 53 | end 54 | 55 | # A list of parameters that should be filtered out of what is sent to Airbrake. 56 | # By default, all "password" attributes will have their contents replaced. 57 | # https://github.com/airbrake/airbrake-ruby#blacklist_keys 58 | Airbrake.blacklist_keys(/password/i) 59 | 60 | # If Airbrake doesn't send any expected exceptions, we suggest to uncomment the 61 | # line below. It might simplify debugging of background Airbrake workers, which 62 | # can silently die. 63 | # Thread.abort_on_exception = ['test', 'development'].include?(Rails.env) 64 | -------------------------------------------------------------------------------- /spec/unit/rack/notice_builder_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Airbrake::Rack::NoticeBuilder do 4 | describe "#build_notice" do 5 | it "doesn't overwrite session with nil" do 6 | notice_builder = described_class.new('rack.session' => nil) 7 | notice = notice_builder.build_notice(AirbrakeTestError.new) 8 | 9 | expect(notice[:session]).to eq({}) 10 | end 11 | 12 | it "sets session if it is present" do 13 | session = { a: 1, b: 2 } 14 | notice_builder = described_class.new('rack.session' => session) 15 | notice = notice_builder.build_notice(AirbrakeTestError.new) 16 | 17 | expect(notice[:session]).to eq(session) 18 | end 19 | 20 | it "doesn't overwrite params with nil" do 21 | notice_builder = described_class.new('action_dispatch.request.parameters' => nil) 22 | notice = notice_builder.build_notice(AirbrakeTestError.new) 23 | 24 | expect(notice[:session]).to eq({}) 25 | end 26 | 27 | it "sets params if they're present" do 28 | params = { a: 1, b: 2 } 29 | notice_builder = described_class.new('action_dispatch.request.parameters' => params) 30 | notice = notice_builder.build_notice(AirbrakeTestError.new) 31 | 32 | expect(notice[:params]).to eq(params) 33 | end 34 | 35 | it "adds CONTENT_TYPE, CONTENT_LENGTH and HTTP_* headers in the environment" do 36 | headers = { 37 | "HTTP_HOST" => "example.com", 38 | "CONTENT_TYPE" => "text/html", 39 | "CONTENT_LENGTH" => 100500 40 | } 41 | notice_builder = described_class.new(headers.dup) 42 | notice = notice_builder.build_notice(AirbrakeTestError.new) 43 | expect(notice[:environment][:headers]).to eq(headers) 44 | end 45 | 46 | it "skips headers that were not selected to be stored in the environment" do 47 | headers = { 48 | "HTTP_HOST" => "example.com", 49 | "CONTENT_TYPE" => "text/html", 50 | "CONTENT_LENGTH" => 100500 51 | } 52 | notice_builder = described_class.new(headers.merge("X-SOME-HEADER" => "value")) 53 | notice = notice_builder.build_notice(AirbrakeTestError.new) 54 | expect(notice[:environment][:headers]).to eq(headers) 55 | end 56 | 57 | it "preserves data that already has been added to the environment" do 58 | headers = { 59 | "HTTP_HOST" => "example.com", 60 | "CONTENT_TYPE" => "text/html", 61 | "CONTENT_LENGTH" => 100500 62 | } 63 | allow(Airbrake).to receive(:build_notice).and_wrap_original do |method, *args| 64 | notice = method.call(*args) 65 | notice[:environment]["SOME_KEY"] = "SOME_VALUE" 66 | notice 67 | end 68 | notice_builder = described_class.new(headers) 69 | notice = notice_builder.build_notice(AirbrakeTestError.new) 70 | expect(notice[:environment]["SOME_KEY"]).to eq("SOME_VALUE") 71 | end 72 | 73 | it "runs user defined builders against notices" do 74 | extended_class = described_class.dup 75 | extended_class.add_builder do |notice, request| 76 | notice[:params][:remoteIp] = request.env['REMOTE_IP'] 77 | end 78 | notice_builder = extended_class.new('REMOTE_IP' => '127.0.0.1') 79 | notice = notice_builder.build_notice(AirbrakeTestError.new) 80 | expect(notice[:params][:remoteIp]).to eq("127.0.0.1") 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Airbrake Changelog 2 | ================== 3 | 4 | ### master 5 | 6 | * Fixed bug when trying to send a test exception with help of the Rake task 7 | results in an error due to the current environment being ignored 8 | ([#523](https://github.com/airbrake/airbrake/pull/523)) 9 | 10 | ### [v5.1.0][v5.1.0] (February 29, 2016) 11 | 12 | * Fixed Rake integration sometimes not reporting errors 13 | ([#513](https://github.com/airbrake/airbrake/pull/513)) 14 | * Added a way to attach custom information to notices from Rack requests 15 | ([#517](https://github.com/airbrake/airbrake/pull/517)) 16 | * Added support for Goliath apps (fixes regression from Airbrake v4) 17 | ([#519](https://github.com/airbrake/airbrake/pull/519)) 18 | 19 | ### [v5.0.5][v5.0.5] (February 9, 2016) 20 | 21 | * Fixes issue in the Rack integration when `current_user` is `nil` and we try to 22 | build from it ([#501](https://github.com/airbrake/airbrake/pull/501)) 23 | * Improve the Rack integration by attaching more useful debugging information 24 | such as HTTP headers and HTTP methods 25 | ([#499](https://github.com/airbrake/airbrake/pull/499)) 26 | 27 | ### [v5.0.4][v5.0.4] (February 2, 2016) 28 | 29 | * Set RACK_ENV and RAILS_ENV in Capistrano 2 integration 30 | ([#489](https://github.com/airbrake/airbrake/pull/489)) 31 | * Removed the hostname information from the Rack integration because the new 32 | `airbrake-ruby` sends it by default 33 | ([#495](https://github.com/airbrake/airbrake/pull/495)) 34 | 35 | ### [v5.0.3][v5.0.3] (January 19, 2016) 36 | 37 | * Improved RubyMine support 38 | ([#469](https://github.com/airbrake/airbrake/pull/469)) 39 | * Added better support for user reporting for Rails applications (including 40 | OmniAuth support) ([#466](https://github.com/airbrake/airbrake/pull/466)) 41 | * Fixed the Capistrano 2 integration, which was not working at all 42 | ([#475](https://github.com/airbrake/airbrake/pull/475)) 43 | 44 | ### [v5.0.2][v5.0.2] (January 3, 2016) 45 | 46 | * Fixed the bug when Warden user is `nil` 47 | ([#455](https://github.com/airbrake/airbrake/pull/455)) 48 | 49 | ### [v5.0.1][v5.0.1] (December 21, 2015) 50 | 51 | * Fixed Migration Guide discrepancies with regard to Resque and Capistrano 52 | * Using the Capistrano 3 integration, made Airbrake notify of deployments only 53 | from primary server ([#433](https://github.com/airbrake/airbrake/pull/443)) 54 | 55 | ### [v5.0.0][v5.0.0] (December 18, 2015) 56 | 57 | * Minor styling/docs tweaks. No bugs were discovered. 58 | 59 | ### [v5.0.0.rc.1][v5.0.0.rc.1] (December 11, 2015) 60 | 61 | * Version 5 is written from scratch. For the detailed review of the changes see 62 | [docs/Migration_guide_from_v4_to_v5](docs/Migration_guide_from_v4_to_v5.md) 63 | * For the changes made before v5.0.0, see 64 | [docs/CHANGELOG-pre-v5](docs/CHANGELOG-pre-v5.txt). 65 | 66 | [v5.0.0.rc.1]: https://github.com/airbrake/airbrake/releases/tag/v5.0.0.rc.1 67 | [v5.0.0]: https://github.com/airbrake/airbrake/releases/tag/v5.0.0 68 | [v5.0.1]: https://github.com/airbrake/airbrake/releases/tag/v5.0.1 69 | [v5.0.2]: https://github.com/airbrake/airbrake/releases/tag/v5.0.2 70 | [v5.0.3]: https://github.com/airbrake/airbrake/releases/tag/v5.0.3 71 | [v5.0.4]: https://github.com/airbrake/airbrake/releases/tag/v5.0.4 72 | [v5.0.5]: https://github.com/airbrake/airbrake/releases/tag/v5.0.5 73 | [v5.1.0]: https://github.com/airbrake/airbrake/releases/tag/v5.1.0 74 | -------------------------------------------------------------------------------- /lib/airbrake/rake/tasks.rb: -------------------------------------------------------------------------------- 1 | namespace :airbrake do 2 | desc 'Verify your gem installation by sending a test exception' 3 | task test: :environment do 4 | require 'pp' 5 | 6 | begin 7 | raise StandardError, 'Exception from the test Rake task' 8 | rescue => ex 9 | response = Airbrake.notify_sync(ex) 10 | end 11 | 12 | notifiers = Airbrake.instance_variable_get(:@notifiers).map do |name, notif| 13 | cfg = notif.instance_variable_get(:@config) 14 | filters = notif.instance_variable_get(:@filter_chain) 15 | "#{name}:\n " + [cfg, filters].pretty_inspect 16 | end.join("\n") 17 | 18 | if response 19 | puts < warden)) 33 | expect(retval).to be_a(described_class) 34 | end 35 | 36 | context "and the warden user is nil" do 37 | it "returns nil" do 38 | warden = instance_double('Warden::Proxy') 39 | allow(warden).to receive(:user) { nil } 40 | 41 | retval = described_class.extract(env_for('/', 'warden' => warden)) 42 | expect(retval).to be_nil 43 | end 44 | end 45 | end 46 | 47 | context "when the user was not found" do 48 | it "returns nil" do 49 | retval = described_class.extract(env_for('/')) 50 | expect(retval).to be_nil 51 | end 52 | end 53 | 54 | context "when the current_user Rails controller method is defined" do 55 | context "and it is nil" do 56 | it "returns nil" do 57 | controller = instance_double('DummyController') 58 | env = env_for('/', 'action_controller.instance' => controller) 59 | allow(controller).to receive(:current_user) { nil } 60 | 61 | retval = described_class.extract(env) 62 | expect(retval).to be_nil 63 | end 64 | end 65 | 66 | context "and it is not nil" do 67 | it "returns the wrapped user" do 68 | controller = instance_double('DummyController') 69 | env = env_for('/', 'action_controller.instance' => controller) 70 | allow(controller).to receive(:current_user) { user } 71 | 72 | retval = described_class.extract(env) 73 | expect(retval).to be_a(described_class) 74 | end 75 | end 76 | end 77 | end 78 | 79 | describe "#as_json" do 80 | context "when Rack user contains all expect fields" do 81 | let(:user_data) { described_class.new(user).as_json[:user] } 82 | 83 | it "contains the 'id' key" do 84 | expect(user_data).to include(:id) 85 | end 86 | 87 | it "contains the 'name' key" do 88 | expect(user_data).to include(:name) 89 | end 90 | 91 | it "contains the 'username' key" do 92 | expect(user_data).to include(:username) 93 | end 94 | 95 | it "contains the 'email' key" do 96 | expect(user_data).to include(:email) 97 | end 98 | end 99 | 100 | context "when Rack user doesn't contain any of the expect fields" do 101 | let(:user_data) { described_class.new(OpenStruct.new).as_json } 102 | 103 | it "is empty" do 104 | expect(user_data).to be_empty 105 | end 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Gems from the gemspec. 2 | require 'webmock' 3 | require 'webmock/rspec' 4 | require 'rspec/wait' 5 | require 'pry' 6 | require 'rack' 7 | require 'rack/test' 8 | require 'rake' 9 | 10 | if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0') 11 | require 'sidekiq' 12 | require 'sidekiq/cli' 13 | end 14 | 15 | require 'airbrake' 16 | require 'airbrake/rake/tasks' 17 | 18 | # Load integration tests only when they're run through appraisals. 19 | if ENV['APPRAISAL_INITIALIZED'] 20 | # Gems from appraisals that every application uses. 21 | require 'warden' 22 | 23 | # Load a Rails app or skip. 24 | begin 25 | ENV['RAILS_ENV'] = 'test' 26 | 27 | if RUBY_ENGINE == 'jruby' 28 | require 'activerecord-jdbcsqlite3-adapter' 29 | else 30 | require 'sqlite3' 31 | end 32 | 33 | require 'rails' 34 | 35 | rails_vsn = Gem::Version.new(Rails.version) 36 | 37 | ENV['DATABASE_URL'] = if rails_vsn <= Gem::Version.new('4.2') 38 | 'sqlite3:///:memory:' 39 | else 40 | 'sqlite3::memory:' 41 | end 42 | 43 | require 'action_controller' 44 | require 'action_view' 45 | require 'action_view/testing/resolvers' 46 | require 'active_record/railtie' 47 | if rails_vsn >= Gem::Version.new('4.2') 48 | require 'active_job' 49 | 50 | # Silence logger. 51 | ActiveJob::Base.logger.level = 99 52 | end 53 | 54 | require 'resque' 55 | require 'resque_spec' 56 | require 'airbrake/resque/failure' 57 | Resque::Failure.backend = Resque::Failure::Airbrake 58 | 59 | require 'delayed_job' 60 | require 'delayed_job_active_record' 61 | require 'airbrake/delayed_job/plugin' 62 | Delayed::Worker.delay_jobs = false 63 | 64 | require 'airbrake/rails/railtie' 65 | 66 | load 'apps/rails/dummy_task.rake' 67 | require 'apps/rails/dummy_app' 68 | rescue LoadError 69 | puts '** Skipped Rails specs' 70 | end 71 | 72 | # Load a Sinatra app or skip. 73 | begin 74 | # Resque depends on Sinatra, so when we launch Rails specs, we also 75 | # accidentally load Sinatra. 76 | raise LoadError if defined?(Resque) 77 | 78 | require 'sinatra' 79 | require 'apps/sinatra/dummy_app' 80 | rescue LoadError 81 | puts '** Skipped Sinatra specs' 82 | end 83 | 84 | # Load a Rack app or skip. 85 | begin 86 | require 'apps/rack/dummy_app' 87 | rescue LoadError 88 | puts '** Skipped Rack specs' 89 | end 90 | end 91 | 92 | RSpec.configure do |c| 93 | c.order = 'random' 94 | c.color = true 95 | c.disable_monkey_patching! 96 | c.wait_timeout = 3 97 | 98 | c.include Rack::Test::Methods 99 | end 100 | 101 | Airbrake.configure do |c| 102 | c.project_id = 113743 103 | c.project_key = 'fd04e13d806a90f96614ad8e529b2822' 104 | c.logger = Logger.new('/dev/null') 105 | c.app_version = '1.2.3' 106 | c.workers = 5 107 | end 108 | 109 | # Make sure tests that use async requests fail. 110 | Thread.abort_on_exception = true 111 | 112 | AirbrakeTestError = Class.new(StandardError) 113 | 114 | # Print header with versions information. This simplifies debugging of build 115 | # failures on CircleCI. 116 | versions = <] the list of notice's builders 12 | attr_reader :builders 13 | 14 | ## 15 | # Adds user defined builders to the chain. 16 | def add_builder(&block) 17 | @builders << block 18 | end 19 | end 20 | 21 | ## 22 | # @return [Array] the prefixes of the majority of HTTP headers in 23 | # Rack (some prefixes match the header names for simplicity) 24 | HTTP_HEADER_PREFIXES = [ 25 | 'HTTP_'.freeze, 26 | 'CONTENT_TYPE'.freeze, 27 | 'CONTENT_LENGTH'.freeze 28 | ].freeze 29 | 30 | ## 31 | # @param [Hash{String=>Object}] rack_env The Rack environment 32 | def initialize(rack_env) 33 | @request = ::Rack::Request.new(rack_env) 34 | end 35 | 36 | ## 37 | # Adds context, session, params and other fields based on the Rack env. 38 | # 39 | # @param [Exception] exception 40 | # @return [Airbrake::Notice] the notice with extra information 41 | def build_notice(exception) 42 | notice = Airbrake.build_notice(exception) 43 | NoticeBuilder.builders.each { |builder| builder.call(notice, @request) } 44 | notice 45 | end 46 | 47 | # Adds context (url, user agent, framework version, controller, etc) 48 | add_builder do |notice, request| 49 | context = notice[:context] 50 | 51 | context[:url] = request.url 52 | context[:userAgent] = request.user_agent 53 | 54 | framework_version = 55 | if defined?(::Rails) 56 | "Rails/#{::Rails.version}" 57 | elsif defined?(::Sinatra) 58 | "Sinatra/#{Sinatra::VERSION}" 59 | else 60 | "Rack.version/#{::Rack.version} Rack.release/#{::Rack.release}" 61 | end.freeze 62 | 63 | if context.key?(:version) 64 | context[:version] += " #{framework_version}" 65 | else 66 | context[:version] = framework_version 67 | end 68 | 69 | controller = request.env['action_controller.instance'] 70 | if controller 71 | context[:component] = controller.controller_name 72 | context[:action] = controller.action_name 73 | end 74 | 75 | user = Airbrake::Rack::User.extract(request.env) 76 | notice[:context].merge!(user.as_json) if user 77 | 78 | nil 79 | end 80 | 81 | # Adds session 82 | add_builder do |notice, request| 83 | session = request.session 84 | notice[:session] = session if session 85 | end 86 | 87 | # Adds request params 88 | add_builder do |notice, request| 89 | params = request.env['action_dispatch.request.parameters'] 90 | notice[:params] = params if params 91 | end 92 | 93 | # Adds http referer, method and headers to the environment 94 | add_builder do |notice, request| 95 | http_headers = request.env.map.with_object({}) do |(key, value), headers| 96 | if HTTP_HEADER_PREFIXES.any? { |prefix| key.to_s.start_with?(prefix) } 97 | headers[key] = value 98 | end 99 | 100 | headers 101 | end 102 | 103 | notice[:environment].merge!( 104 | httpMethod: request.request_method, 105 | referer: request.referer, 106 | headers: http_headers 107 | ) 108 | end 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /spec/integration/shared_examples/rack_examples.rb: -------------------------------------------------------------------------------- 1 | RSpec.shared_examples 'rack examples' do 2 | include Warden::Test::Helpers 3 | 4 | after { Warden.test_reset! } 5 | 6 | let(:endpoint) do 7 | 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822' 8 | end 9 | 10 | def wait_for_a_request_with_body(body) 11 | wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once 12 | end 13 | 14 | before do 15 | stub_request(:post, endpoint).to_return(status: 201, body: '{}') 16 | end 17 | 18 | describe "application routes" do 19 | describe "/index" do 20 | it "successfully returns 200 and body" do 21 | get '/' 22 | 23 | expect(last_response.status).to eq(200) 24 | expect(last_response.body).to eq('Hello from index') 25 | 26 | wait_for(a_request(:post, endpoint)).not_to have_been_made 27 | end 28 | end 29 | 30 | describe "/crash" do 31 | it "returns 500 and sends a notice to Airbrake" do 32 | get '/crash' 33 | 34 | expect(last_response.status).to eq(500) 35 | wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/) 36 | end 37 | end 38 | end 39 | 40 | describe "context payload" do 41 | context "when the user is present" do 42 | let(:common_user_params) do 43 | { id: 1, email: 'qa@example.com', username: 'qa-dept' } 44 | end 45 | 46 | before do 47 | login_as(OpenStruct.new(user_params)) 48 | get '/crash' 49 | end 50 | 51 | context "when the user has first and last names" do 52 | let(:user_params) do 53 | common_user_params.merge(first_name: 'Bingo', last_name: 'Bongo') 54 | end 55 | 56 | it "reports the user's first and last names" do 57 | wait_for_a_request_with_body(/ 58 | "context":{.* 59 | "user":{ 60 | "id":"1", 61 | "name":"Bingo\sBongo", 62 | "username":"qa-dept", 63 | "email":"qa@example.com"} 64 | /x) 65 | end 66 | end 67 | 68 | context "when the user has only name" do 69 | let(:user_params) do 70 | common_user_params.merge(name: 'Bingo') 71 | end 72 | 73 | it "reports the user's name" do 74 | wait_for_a_request_with_body(/ 75 | "context":{.* 76 | "user":{ 77 | "id":"1", 78 | "name":"Bingo", 79 | "username":"qa-dept", 80 | "email":"qa@example.com"} 81 | /x) 82 | end 83 | end 84 | end 85 | 86 | context "when additional parameters present" do 87 | before do 88 | get '/crash', nil, 'HTTP_USER_AGENT' => 'Bot', 'HTTP_REFERER' => 'bingo.com' 89 | end 90 | 91 | it "features url" do 92 | wait_for_a_request_with_body( 93 | %r("context":{.*"url":"http://example\.org/crash".*}) 94 | ) 95 | end 96 | 97 | it "features hostname" do 98 | wait_for_a_request_with_body(/"context":{.*"hostname":".+".*}/) 99 | end 100 | 101 | it "features userAgent" do 102 | wait_for_a_request_with_body(/"context":{.*"userAgent":"Bot".*}/) 103 | end 104 | end 105 | end 106 | 107 | describe "environment payload" do 108 | before do 109 | get '/crash', nil, 'HTTP_REFERER' => 'bingo.com' 110 | end 111 | 112 | it "features referer" do 113 | wait_for_a_request_with_body(/"environment":{.*"referer":"bingo.com".*}/) 114 | end 115 | 116 | it "contains HTTP headers" do 117 | wait_for_a_request_with_body( 118 | /"environment":{.*"headers":{.*"CONTENT_LENGTH":"0".*}/ 119 | ) 120 | end 121 | 122 | it "contains HTTP method" do 123 | wait_for_a_request_with_body(/"environment":{.*"httpMethod":"GET".*}/) 124 | end 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /spec/apps/rails/dummy_app.rb: -------------------------------------------------------------------------------- 1 | class DummyApp < Rails::Application 2 | # Rails requires these two keys. 3 | config.session_store :cookie_store, key: 'jiez4Mielu1AiHugog3shiiPhe3lai3faer' 4 | config.secret_token = 'ni6aeph6aeriBiphesh8omahv6cohpue5Quah5ceiMohtuvei8' 5 | 6 | if Gem::Version.new(Rails.version) > Gem::Version.new('3.2.0') 7 | config.secret_key_base = '62773890cad9d9d584b57320f8612f8f7378a90aadcabc6ee' 8 | end 9 | 10 | # Configure a logger, without it the tests can't run. 11 | vsn = Rails.version.split('').values_at(0, 2).join('') 12 | log_path = File.join(File.dirname(__FILE__), 'logs', "#{vsn}.log") 13 | config.logger = Logger.new(log_path) 14 | Rails.logger = config.logger 15 | 16 | config.active_support.deprecation = :stderr 17 | 18 | config.middleware.use Warden::Manager 19 | 20 | # In Rails 4.2.x Active Record suppresses errors raised within 21 | # 'after_rollback' & 'after_commit' callbacks and only print them to the 22 | # logs. In the next version, these errors will no longer be suppressed. 23 | # Instead, the errors will propagate normally just like in other Active Record 24 | # callbacks. 25 | config.active_record.raise_in_transactional_callbacks = true if vsn == '42' 26 | 27 | # Silences the warning, which says 'config.eager_load is set to nil'. 28 | config.eager_load = false 29 | 30 | routes.append do 31 | get '/' => 'dummy#index' 32 | get '/crash' => 'dummy#crash' 33 | get '/notify_airbrake_helper' => 'dummy#notify_airbrake_helper' 34 | get '/notify_airbrake_sync_helper' => 'dummy#notify_airbrake_sync_helper' 35 | get '/active_record_after_commit' => 'dummy#active_record_after_commit' 36 | get '/active_record_after_rollback' => 'dummy#active_record_after_rollback' 37 | get '/active_job' => 'dummy#active_job' 38 | get '/resque' => 'dummy#resque' 39 | get '/delayed_job' => 'dummy#delayed_job' 40 | end 41 | end 42 | 43 | class Book < ActiveRecord::Base 44 | after_commit :raise_error_after_commit 45 | after_rollback :raise_error_after_rollback 46 | 47 | def raise_error_after_commit 48 | raise AirbrakeTestError, 'after_commit' 49 | end 50 | 51 | def raise_error_after_rollback 52 | raise AirbrakeTestError, 'after_rollback' 53 | end 54 | end 55 | 56 | # ActiveJob. 57 | if Gem::Version.new(Rails.version) >= Gem::Version.new('4.2') 58 | class BingoJob < ActiveJob::Base 59 | queue_as :bingo 60 | 61 | def perform(*_args) 62 | raise AirbrakeTestError, 'active_job error' 63 | end 64 | end 65 | end 66 | 67 | # Resque. 68 | class BingoWorker 69 | @queue = :bingo_workers_queue 70 | 71 | def self.perform(_bango, _bongo) 72 | raise AirbrakeTestError, 'resque error' 73 | end 74 | end 75 | 76 | # DelayedJob. 77 | BangoJob = Struct.new(:bingo, :bongo) do 78 | def perform 79 | raise AirbrakeTestError, 'delayed_job error' 80 | end 81 | end 82 | 83 | class DummyController < ActionController::Base 84 | layout 'application' 85 | 86 | self.view_paths = [ 87 | ActionView::FixtureResolver.new( 88 | 'layouts/application.html.erb' => '<%= yield %>', 89 | 'dummy/index.html.erb' => 'Hello from index', 90 | 'dummy/notify_airbrake_helper.html.erb' => 'notify_airbrake_helper', 91 | 'dummy/notify_airbrake_sync_helper.html.erb' => 'notify_airbrake_helper_sync', 92 | 'dummy/active_record_after_commit.html.erb' => 'active_record_after_commit', 93 | 'dummy/active_record_after_rollback.html.erb' => 'active_record_after_rollback', 94 | 'dummy/active_job.html.erb' => 'active_job', 95 | 'dummy/resque.html.erb' => 'resque', 96 | 'dummy/delayed_job.html.erb' => 'delayed_job' 97 | ) 98 | ] 99 | 100 | def index 101 | end 102 | 103 | def crash 104 | raise AirbrakeTestError 105 | end 106 | 107 | def notify_airbrake_helper 108 | notify_airbrake(AirbrakeTestError.new) 109 | end 110 | 111 | def notify_airbrake_sync_helper 112 | notify_airbrake_sync(AirbrakeTestError.new) 113 | end 114 | 115 | def active_record_after_commit 116 | Book.create(title: 'Bingo') 117 | end 118 | 119 | def active_record_after_rollback 120 | Book.transaction do 121 | Book.create(title: 'Bango') 122 | raise ActiveRecord::Rollback 123 | end 124 | end 125 | 126 | def active_job 127 | BingoJob.perform_later('bango', 'bongo') 128 | end 129 | 130 | def resque 131 | Resque.enqueue(BingoWorker, 'bango', 'bongo') 132 | end 133 | 134 | def delayed_job 135 | Delayed::Job.enqueue(BangoJob.new('bingo', 'bongo')) 136 | end 137 | end 138 | 139 | # Initializes middlewares and such. 140 | DummyApp.initialize! 141 | 142 | ActiveRecord::Base.connection.create_table(:books) do |t| 143 | t.string(:title) 144 | end 145 | 146 | ActiveRecord::Migration.verbose = false 147 | require 'generators/delayed_job/templates/migration' 148 | ActiveRecord::Schema.define do 149 | CreateDelayedJobs.up 150 | end 151 | -------------------------------------------------------------------------------- /spec/integration/rails/rails_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/shared_examples/rack_examples' 3 | 4 | RSpec.describe "Rails integration specs" do 5 | include Warden::Test::Helpers 6 | 7 | let(:app) { Rails.application } 8 | 9 | include_examples 'rack examples' 10 | 11 | it "inserts the Airbrake Rack middleware after DebugExceptions" do 12 | middlewares = Rails.configuration.middleware.middlewares.map(&:inspect) 13 | own_idx = middlewares.index('Airbrake::Rack::Middleware') 14 | 15 | expect(middlewares[own_idx - 1]).to eq('ActionDispatch::DebugExceptions') 16 | end 17 | 18 | shared_examples 'context payload content' do |route| 19 | before do 20 | login_as(OpenStruct.new(id: 1, email: 'qa@example.com', username: 'qa-dept')) 21 | get(route, foo: :bar) 22 | end 23 | 24 | it "includes component information" do 25 | wait_for_a_request_with_body(/"context":{.*"component":"dummy".*}/) 26 | end 27 | 28 | it "includes action information" do 29 | case route 30 | when '/crash' 31 | wait_for_a_request_with_body(/"context":{.*"action":"crash".*}/) 32 | when '/notify_airbrake_helper' 33 | wait_for_a_request_with_body( 34 | /"context":{.*"action":"notify_airbrake_helper".*}/ 35 | ) 36 | when '/notify_airbrake_sync_helper' 37 | wait_for_a_request_with_body( 38 | /"context":{.*"action":"notify_airbrake_sync_helper".*}/ 39 | ) 40 | else 41 | raise 'Unknown route' 42 | end 43 | end 44 | 45 | it "includes version" do 46 | wait_for_a_request_with_body(/"context":{.*"version":"1.2.3 Rails/) 47 | end 48 | 49 | it "includes session" do 50 | wait_for_a_request_with_body( 51 | /"context":{.*"session":{.*"session_id":"\w+".*}/ 52 | ) 53 | end 54 | 55 | it "includes params" do 56 | action = route[1..-1] 57 | wait_for_a_request_with_body( 58 | /"context":{.*"params":{.*"controller":"dummy","action":"#{action}".*}/ 59 | ) 60 | end 61 | end 62 | 63 | describe "context payload" do 64 | context "when exception reported through middleware" do 65 | include_examples('context payload content', '/crash') 66 | end 67 | 68 | context "when exception reported through the notify_airbrake helper" do 69 | include_examples('context payload content', '/notify_airbrake_helper') 70 | end 71 | 72 | context "when exception reported through the notify_airbrake_sync helper" do 73 | include_examples('context payload content', '/notify_airbrake_sync_helper') 74 | end 75 | end 76 | 77 | describe "Active Record callbacks" do 78 | it "reports exceptions in after_commit callbacks" do 79 | get '/active_record_after_commit' 80 | wait_for_a_request_with_body( 81 | /"type":"AirbrakeTestError","message":"after_commit"/ 82 | ) 83 | end 84 | 85 | it "reports exceptions in after_rollback callbacks" do 86 | get '/active_record_after_rollback' 87 | wait_for_a_request_with_body( 88 | /"type":"AirbrakeTestError","message":"after_rollback"/ 89 | ) 90 | end 91 | end 92 | 93 | if Gem::Version.new(Rails.version) >= Gem::Version.new('4.2') 94 | describe "ActiveJob jobs" do 95 | it "reports exceptions occurring in ActiveJob workers" do 96 | get '/active_job' 97 | sleep 2 98 | 99 | wait_for( 100 | a_request(:post, endpoint). 101 | with(body: /"message":"active_job error"/) 102 | ).to have_been_made.at_least_once 103 | end 104 | end 105 | end 106 | 107 | describe "Resque workers" do 108 | it "reports exceptions occurring in Resque workers" do 109 | with_resque { get '/resque' } 110 | 111 | wait_for_a_request_with_body( 112 | /"message":"resque\serror".*"params":{.* 113 | "class":"BingoWorker","args":\["bango","bongo"\].*}/x 114 | ) 115 | end 116 | end 117 | 118 | # Delayed Job doesn't support Ruby 1.9.2 119 | if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('1.9.2') 120 | describe "DelayedJob jobs" do 121 | it "reports exceptions occurring in DelayedJob jobs" do 122 | get '/delayed_job' 123 | sleep 2 124 | 125 | wait_for_a_request_with_body( 126 | %r("message":"delayed_job\serror".*"params":{.* 127 | "handler":"---\s!ruby/struct:BangoJob\\nbingo:\s 128 | bingo\\nbongo:\sbongo\\n".*})x 129 | ) 130 | 131 | # Two requests are performed during this example. We care only about one. 132 | # Sleep guarantees that we let the unimportant request occur here and not 133 | # elsewhere. 134 | sleep 2 135 | end 136 | end 137 | end 138 | 139 | describe "notice payload when a user is authenticated without Warden" do 140 | context "when the current_user method is defined" do 141 | it "contains the user information" do 142 | user = OpenStruct.new(id: 1, email: 'qa@example.com', username: 'qa-dept') 143 | allow_any_instance_of(DummyController).to receive(:current_user) { user } 144 | 145 | get '/crash' 146 | wait_for_a_request_with_body( 147 | /"user":{"id":"1","username":"qa-dept","email":"qa@example.com"}/ 148 | ) 149 | end 150 | end 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /spec/integration/rails/rake_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "Rake integration" do 4 | let(:endpoint) do 5 | 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822' 6 | end 7 | 8 | def wait_for_a_request_with_body(body) 9 | wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once 10 | end 11 | 12 | def expect_no_requests_with_body(body) 13 | sleep 1 14 | expect(a_request(:post, endpoint).with(body: body)).not_to have_been_made 15 | end 16 | 17 | before do 18 | Rails.application.load_tasks 19 | stub_request(:post, endpoint).to_return(status: 201, body: '{}') 20 | expect { faulty_task.invoke }.to raise_error(AirbrakeTestError) 21 | end 22 | 23 | after do 24 | # Rake ensures that each task is executed only once per session. For testing 25 | # purposes, we run the task multiple times. 26 | faulty_task.reenable 27 | end 28 | 29 | describe "a task with maximum information, which raises an exception" do 30 | let(:faulty_task) { Rake::Task['bingo:bango'] } 31 | 32 | it "sends the exception to Airbrake" do 33 | wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/) 34 | end 35 | 36 | describe "contains the context payload, which" do 37 | it "includes correct component" do 38 | wait_for_a_request_with_body(/"context":{.*"component":"rake".*}/) 39 | end 40 | 41 | it "includes correct action" do 42 | wait_for_a_request_with_body( 43 | /"context":{.*"action":"bingo:bango".*/ 44 | ) 45 | end 46 | end 47 | 48 | describe "contains the params payload, which" do 49 | it "includes a task name" do 50 | wait_for_a_request_with_body( 51 | /"params":{.*"rake_task":{.*"name":"bingo:bango".*}.*}/ 52 | ) 53 | end 54 | 55 | it "includes a timestamp" do 56 | wait_for_a_request_with_body( 57 | /"params":{.*"rake_task":{.*"timestamp":"201\d\-\d\d-\d\d.+".*}.*}/ 58 | ) 59 | end 60 | 61 | it "includes investigation" do 62 | # rubocop:disable Metrics/LineLength 63 | wait_for_a_request_with_body( 64 | /"params":{.*"rake_task":{.*"investigation":".+Investigating bingo:bango.+".*}.*}/ 65 | ) 66 | # rubocop:enable Metrics/LineLength 67 | end 68 | 69 | it "includes full comment" do 70 | wait_for_a_request_with_body( 71 | /"params":{.*"rake_task":{.*"full_comment":"Dummy description".*}.*}/ 72 | ) 73 | end 74 | 75 | it "includes arg names" do 76 | wait_for_a_request_with_body( 77 | /"params":{.*"rake_task":{.*"arg_names":\["dummy_arg"\].*}.*}/ 78 | ) 79 | end 80 | 81 | it "includes arg description" do 82 | wait_for_a_request_with_body( 83 | /"params":{.*"rake_task":{.*"arg_description":"\[dummy_arg\]".*}.*}/ 84 | ) 85 | end 86 | 87 | it "includes locations" do 88 | # rubocop:disable Metrics/LineLength 89 | wait_for_a_request_with_body( 90 | %r("params":{.*"rake_task":{.*"locations":\[".+spec/apps/rails/dummy_task.rake:\d+:in.+"\].*}.*}) 91 | ) 92 | # rubocop:enable Metrics/LineLength 93 | end 94 | 95 | it "includes sources" do 96 | wait_for_a_request_with_body( 97 | /"params":{.*"rake_task":{.*"sources":\["environment"\].*}.*}/ 98 | ) 99 | end 100 | 101 | it "includes prerequisite tasks" do 102 | # rubocop:disable Metrics/LineLength 103 | wait_for_a_request_with_body( 104 | /"params":{.*"rake_task":{.*"prerequisite_tasks":\[{"name":"bingo:environment".+\].*}.*}/ 105 | ) 106 | # rubocop:enable Metrics/LineLength 107 | end 108 | 109 | it "includes argv info" do 110 | wait_for_a_request_with_body( 111 | %r("params":{.*"argv":"--pattern spec/integration/rails/\*_spec.rb".*}) 112 | ) 113 | end 114 | 115 | it "includes #execute args" do 116 | wait_for_a_request_with_body( 117 | /"params":{.*"execute_args":\[\].*}/ 118 | ) 119 | end 120 | end 121 | end 122 | 123 | describe "a task with minimum information, which raises an exception" do 124 | let(:faulty_task) { Rake::Task['bingo:bongo'] } 125 | 126 | describe "doesn't contain in the params payload" do 127 | it "full comment" do 128 | expect_no_requests_with_body( 129 | /"params":{.*"rake_task":{.*"full_comment":"Dummy description".*}.*}/ 130 | ) 131 | end 132 | 133 | it "arg names" do 134 | expect_no_requests_with_body( 135 | /"params":{.*"rake_task":{.*"arg_names":\["dummy_arg"\].*}.*}/ 136 | ) 137 | end 138 | 139 | it "arg description" do 140 | expect_no_requests_with_body( 141 | /"params":{.*"rake_task":{.*"arg_description":"\[dummy_arg\]".*}.*}/ 142 | ) 143 | end 144 | 145 | it "sources" do 146 | expect_no_requests_with_body( 147 | /"params":{.*"rake_task":{.*"sources":\["environment"\].*}.*}/ 148 | ) 149 | end 150 | 151 | it "prerequisite tasks" do 152 | # rubocop:disable Metrics/LineLength 153 | expect_no_requests_with_body( 154 | /"params":{.*"rake_task":{.*"prerequisite_tasks":\[{"name":"bingo:environment".+\].*}.*}/ 155 | ) 156 | # rubocop:enable Metrics/LineLength 157 | end 158 | end 159 | end 160 | end 161 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | java: 3 | version: openjdk7 4 | 5 | dependencies: 6 | cache_directories: 7 | - vendor 8 | override: 9 | - bundle install --path=vendor 10 | - ? | 11 | case $CIRCLE_NODE_INDEX in 12 | 0) 13 | rvm-exec 1.9.3-p551 bundle install --jobs=15 --path=vendor 14 | rvm-exec 1.9.3-p551 bundle exec appraisal install --jobs=15 15 | ;; 16 | 1) 17 | rvm-exec 2.0.0-p645 bundle install --jobs=15 --path=vendor 18 | rvm-exec 2.0.0-p645 bundle exec appraisal install --jobs=15 19 | ;; 20 | 2) 21 | rvm-exec 2.3.0 bundle install --jobs=15 --path=vendor 22 | rvm-exec 2.3.0 bundle exec appraisal install --jobs=15 23 | ;; 24 | 3) 25 | # The 'dev' switch makes JRuby start about 2.5 times faster. 26 | # See: https://github.com/jruby/jruby/wiki/Improving-startup-time 27 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle install --jobs=15 --path=vendor 28 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal install --jobs=15 29 | ;; 30 | 4) 31 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle install --jobs=15 --path=vendor 32 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal install --jobs=15 33 | ;; 34 | 5) 35 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle install --jobs=15 --path=vendor 36 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal install --jobs=15 37 | ;; 38 | esac 39 | : 40 | parallel: true 41 | 42 | test: 43 | override: 44 | - ? | 45 | set -e 46 | case $CIRCLE_NODE_INDEX in 47 | 0) 48 | rvm-exec 1.9.3-p551 bundle exec appraisal rails-3.2 rake spec:integration:rails 49 | rvm-exec 1.9.3-p551 bundle exec appraisal rails-4.0 rake spec:integration:rails 50 | rvm-exec 1.9.3-p551 bundle exec appraisal rails-4.1 rake spec:integration:rails 51 | rvm-exec 1.9.3-p551 bundle exec appraisal rails-4.2 rake spec:integration:rails 52 | 53 | rvm-exec 1.9.3-p551 bundle exec appraisal sinatra rake spec:integration:sinatra 54 | 55 | rvm-exec 1.9.3-p551 bundle exec appraisal rack rake spec:integration:rack 56 | ;; 57 | 1) 58 | rvm-exec 2.0.0-p645 bundle exec appraisal rails-3.2 rake spec:integration:rails 59 | rvm-exec 2.0.0-p645 bundle exec appraisal rails-4.0 rake spec:integration:rails 60 | rvm-exec 2.0.0-p645 bundle exec appraisal rails-4.1 rake spec:integration:rails 61 | rvm-exec 2.0.0-p645 bundle exec appraisal rails-4.2 rake spec:integration:rails 62 | 63 | rvm-exec 2.0.0-p645 bundle exec appraisal sinatra rake spec:integration:sinatra 64 | 65 | rvm-exec 2.0.0-p645 bundle exec appraisal rack rake spec:integration:rack 66 | ;; 67 | 2) 68 | rvm-exec 2.3.0 bundle exec appraisal rails-3.2 rake spec:integration:rails 69 | rvm-exec 2.3.0 bundle exec appraisal rails-4.0 rake spec:integration:rails 70 | rvm-exec 2.3.0 bundle exec appraisal rails-4.1 rake spec:integration:rails 71 | rvm-exec 2.3.0 bundle exec appraisal rails-4.2 rake spec:integration:rails 72 | rvm-exec 2.3.0 bundle exec appraisal rails-edge rake spec:integration:rails 73 | 74 | rvm-exec 2.3.0 bundle exec appraisal sinatra rake spec:integration:sinatra 75 | 76 | rvm-exec 2.3.0 bundle exec appraisal rack rake spec:integration:rack 77 | ;; 78 | 3) 79 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal rails-3.2 rake spec:integration:rails 80 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal rails-4.0 rake spec:integration:rails 81 | ;; 82 | 4) 83 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal rails-4.1 rake spec:integration:rails 84 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal rails-4.2 rake spec:integration:rails 85 | ;; 86 | 5) 87 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal sinatra rake spec:integration:sinatra 88 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec appraisal rack rake spec:integration:rack 89 | ;; 90 | esac 91 | : 92 | parallel: true 93 | - ? | 94 | set -e 95 | case $CIRCLE_NODE_INDEX in 96 | 0) 97 | rvm-exec 1.9.3-p551 bundle exec rake spec:unit 98 | ;; 99 | 1) 100 | rvm-exec 2.0.0-p645 bundle exec rake spec:unit 101 | ;; 102 | 2) 103 | rvm-exec 2.3.0 bundle exec rake spec:unit 104 | ;; 105 | 3) 106 | JRUBY_OPTS="--dev -Xcompile.invokedynamic=false -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-noverify -Xcompile.mode=OFF" rvm-exec jruby-9.0.4.0 bundle exec rake spec:unit 107 | ;; 108 | esac 109 | : 110 | parallel: true 111 | 112 | post: 113 | - bundle exec rubocop 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Airbrake 2 | ======== 3 | 4 | [![Build Status](https://circleci.com/gh/airbrake/airbrake-gem.png?circle-token=97d268fcbb02dacb817dbc01e91d119500c360f5&style=shield)](https://circleci.com/gh/airbrake/airbrake-gem) 5 | [![semver]](http://semver.org) 6 | [![Documentation Status](http://inch-ci.org/github/airbrake/airbrake.svg?branch=master)](http://inch-ci.org/github/airbrake/airbrake) 7 | [![PR Stats](http://issuestats.com/github/airbrake/airbrake/badge/pr?style=flat)](http://issuestats.com/github/airbrake/airbrake) 8 | [![Issue Stats](http://issuestats.com/github/airbrake/airbrake/badge/issue?style=flat)](http://issuestats.com/github/airbrake/airbrake) 9 | 10 | ![The Airbrake notifier for Ruby][arthur-ruby] 11 | 12 | * [Airbrake README](https://github.com/airbrake/airbrake) 13 | * [Airbrake Ruby README](https://github.com/airbrake/airbrake-ruby) 14 | * [YARD API documentation](http://www.rubydoc.info/gems/airbrake-ruby) 15 | * [**Migration guide from v4 to v5**][migration-guide] 16 | 17 | Introduction 18 | ------------ 19 | 20 | [Airbrake][airbrake.io] is an online tool that provides robust exception 21 | tracking in any of your Ruby applications. In doing so, it allows you to easily 22 | review errors, tie an error to an individual piece of code, and trace the cause 23 | back to recent changes. The Airbrake dashboard provides easy categorization, 24 | searching, and prioritization of exceptions so that when errors occur, your team 25 | can quickly determine the root cause. 26 | 27 | Looking for the old version? 28 | ---------------------------- 29 | 30 | Airbrake V5 was released on 18th December 2015. Here is a guide for 31 | [migrating from v4 to v5][migration-guide]. 32 | 33 | You can find the [V4 code 34 | here](https://github.com/airbrake/airbrake/tree/airbrake-v4). 35 | 36 | Key features 37 | ------------ 38 | 39 | ![The Airbrake Dashboard][dashboard] 40 | 41 | This library is built on top of [Airbrake Ruby][airbrake-ruby]. The difference 42 | between _Airbrake_ and _Airbrake Ruby_ is that the `airbrake` gem is just a 43 | collection of integrations with frameworks or other libraries. The 44 | `airbrake-ruby` gem is the core library that performs exception sending and 45 | other heavy lifting. 46 | 47 | Normally, you just need to depend on this gem, select the integration you are 48 | interested in and follow the instructions for it. If you develop a pure 49 | frameworkless Ruby application or embed Ruby and don't need any of the listed 50 | integrations, you can depend on the `airbrake-ruby` gem and ignore this gem 51 | entirely. 52 | 53 | The list of integrations that are available in this gem includes: 54 | 55 | * [Heroku support][heroku-docs] (as an [add-on][heroku-addon]) 56 | * Web frameworks 57 | * Rails[[link](#rails)] 58 | * Sinatra[[link](#sinatra)] 59 | * Rack applications[[link](#rack)] 60 | * Job processing libraries 61 | * ActiveJob[[link](#activejob)] 62 | * Resque[[link](#resque)] 63 | * Sidekiq[[link](#sidekiq)] 64 | * DelayedJob[[link](#delayedjob)] 65 | * Other libraries 66 | * Rake[[link](#rake)] 67 | * Plain Ruby scripts[[link](#plain-ruby-scripts)] 68 | 69 | [Paying Airbrake plans][pricing] support the ability to track deployments of 70 | your application in Airbrake. We offer several ways to track your deployments: 71 | 72 | * Using Capistrano[[link](#capistrano)] 73 | * Using the Rake task[[link](#rake-task)] 74 | 75 | Installation 76 | ------------ 77 | 78 | ### Bundler 79 | 80 | Add the Airbrake gem to your Gemfile: 81 | 82 | ```ruby 83 | gem 'airbrake', '~> 5.1' 84 | ``` 85 | 86 | ### Manual 87 | 88 | Invoke the following command from your terminal: 89 | 90 | ```bash 91 | gem install airbrake 92 | ``` 93 | 94 | Configuration 95 | ------------- 96 | 97 | ### Rails 98 | 99 | #### Airbrake v5 is already here (but we still support Airbrake v4) 100 | 101 | If you are migrating from Airbrake v4, please [read our migration 102 | guide][migration-guide]. 103 | 104 | Since the 5th major release of the Airbrake gem we support only Rails 3.2+ and 105 | Ruby 1.9+. Don't worry, if you use older versions of Rails or Ruby, just 106 | continue using them with Airbrake v4: we _still_ support it. However, v4 is 107 | _feature frozen_. We accept only bugfixes. 108 | 109 | In the meantime, consider upgrading to Airbrake v5, as you miss a lot of new 110 | features, such as support for multiple Airbrake configurations inside one Rails 111 | project (you can report to different Airbrake projects in the same Ruby 112 | process), nested exceptions, multiple asynchronous workers support, JRuby's Java 113 | exceptions and many more. 114 | 115 | #### Integration 116 | 117 | To integrate Airbrake with your Rails application, you need to know 118 | your [project id and project key][project-idkey]. Invoke the following command 119 | and replace `PROJECT_ID` and `PROJECT_KEY` with your values: 120 | 121 | ```bash 122 | rails g airbrake PROJECT_ID PROJECT_KEY 123 | ``` 124 | 125 | [Heroku add-on][heroku-addon] users can omit specifying the key and the id and invoke 126 | the command without arguments (Heroku add-on's environment variables will be 127 | used) ([Heroku add-on docs][heroku-docs]): 128 | 129 | ```bash 130 | rails g airbrake 131 | ``` 132 | 133 | This command will generate the Airbrake configuration file under 134 | `config/initializers/airbrake.rb`. Make sure that this file is checked into your 135 | version control system. This is enough to start Airbraking. 136 | 137 | In order to configure the library according to your needs, open up the file and 138 | edit it. [The full list of supported configuration options][config] is available 139 | online. 140 | 141 | To test the integration, invoke a special Rake task that we provide: 142 | 143 | ```ruby 144 | rake airbrake:test 145 | ``` 146 | 147 | In case of success, a test exception should appear in your dashboard. 148 | 149 | #### The notify_airbrake controller helpers 150 | 151 | The Airbrake gem defines two helper methods available inside Rails controllers: 152 | `#notify_airbrake` and `#notify_airbrake_sync`. If you want to notify Airbrake 153 | from your controllers manually, it's usually a good idea to prefer them over 154 | `Airbrake.notify`, because they automatically add information from the Rack 155 | environment to notices. `#notify_airbrake` is asynchronous (immediately returns 156 | `nil`), while `#notify_airbrake_sync` is synchronous (waits for responses from 157 | the server and returns them). The list of accepted arguments is identical to 158 | `Airbrake.notify`. 159 | 160 | #### Additional features: user reporting, sophisticated API 161 | 162 | The library sends all uncaught exceptions automatically, attaching the maximum 163 | possible amount information that can help you to debug errors. The Airbrake gem 164 | is capable of reporting information about the currently logged in user (id, 165 | email, username, etc.), if you use an authentication library such as Devise. The 166 | library also provides a special API for manual error 167 | reporting. [The description of the API][airbrake-api] is available online. 168 | 169 | #### Automatic integration with Rake tasks and Rails runner 170 | 171 | Additionally, the Rails integration offers automatic exception reporting in any 172 | Rake tasks[[link](#rake)] and [Rails runner][rails-runner]. 173 | 174 | ### Sinatra 175 | 176 | To use Airbrake with Sinatra, simply `require` the gem, [configure][config] it 177 | and `use` our Rack middleware. 178 | 179 | ```ruby 180 | # myapp.rb 181 | require 'sinatra/base' 182 | require 'airbrake' 183 | 184 | Airbrake.configure do |c| 185 | c.project_id = 113743 186 | c.project_key = 'fd04e13d806a90f96614ad8e529b2822' 187 | 188 | # Display debug output. 189 | c.logger.level = Logger::DEBUG 190 | end 191 | 192 | class MyApp < Sinatra::Base 193 | use Airbrake::Rack::Middleware 194 | 195 | get('/') { 1/0 } 196 | end 197 | 198 | run MyApp.run! 199 | ``` 200 | 201 | To run the app, add a file called `config.ru` to the same directory and invoke 202 | `rackup` from your console. 203 | 204 | ```ruby 205 | # config.ru 206 | require_relative 'myapp' 207 | ``` 208 | 209 | That's all! Now you can send a test request to `localhost:9292` and check your 210 | project's dashboard for a new error. 211 | 212 | ```bash 213 | curl localhost:9292 214 | ``` 215 | 216 | ### Rack 217 | 218 | To send exceptions to Airbrake from any Rack application, simply `use` our Rack 219 | middleware, and [configure][config] the default notifier. 220 | 221 | ```ruby 222 | require 'airbrake' 223 | 224 | Airbrake.configure do |c| 225 | c.project_id = 113743 226 | c.project_key = 'fd04e13d806a90f96614ad8e529b2822' 227 | end 228 | 229 | use Airbrake::Rack::Middleware 230 | ``` 231 | 232 | If you want to append additional information from web requests (such as HTTP 233 | headers), define a special hook: 234 | 235 | ```ruby 236 | Airbrake.add_rack_builder do |notice, request| 237 | notice[:params][:remoteIp] = request.env['REMOTE_IP'] 238 | end 239 | ``` 240 | 241 | `request` here is a normal Rack request. 242 | 243 | ### Sidekiq 244 | 245 | We support Sidekiq v2, v3 and v4. The configurations steps for them are 246 | identical. Simply `require` our error handler and you're done: 247 | 248 | ```ruby 249 | require 'airbrake/sidekiq/error_handler' 250 | ``` 251 | 252 | If you required Sidekiq before Airbrake, then you don't even have to `require` 253 | anything manually and it should just work out-of-box. 254 | 255 | ### ActiveJob 256 | 257 | No additional configuration is needed. Simply ensure that you have configured 258 | your Airbrake notifier. 259 | 260 | ### Resque 261 | 262 | Since Airbrake v5 the gem provides its own failure backend. The old way of 263 | integrating Resque doesn't work. If you upgrade to Airbrake v5, just make sure 264 | that you require `airbrake/resque/failure` instead of 265 | `resque/failure/airbrake`. The rest remains the same. 266 | 267 | #### Integrating with Rails applications 268 | 269 | If you're working with Resque in the context of a Rails application, create a 270 | new initializer in `config/initializers/resque.rb` with the following content: 271 | 272 | ```ruby 273 | # config/initializers/resque.rb 274 | require 'airbrake/resque/failure' 275 | Resque::Failure.backend = Resque::Failure::Airbrake 276 | ``` 277 | 278 | That's all configuration. 279 | 280 | #### General integration 281 | 282 | Any Ruby app using Resque can be integrated with Airbrake. If you can require 283 | the Airbrake gem *after* Resque, then there's no need to require 284 | `airbrake/resque/failure` anymore: 285 | 286 | ```ruby 287 | require 'resque' 288 | require 'airbrake' 289 | 290 | Resque::Failure.backend = Resque::Failure::Airbrake 291 | ``` 292 | 293 | If you're unsure, just configure it similar to the Rails approach. If you use 294 | multiple backends, then continue reading the needed configuration steps in 295 | [the Resque wiki][resque-wiki] (it's fairly straightforward). 296 | 297 | ### DelayedJob 298 | 299 | Simply `require` our plugin and you're done: 300 | 301 | ```ruby 302 | require 'airbrake/delayed_job/plugin' 303 | ``` 304 | 305 | If you required DelayedJob before Airbrake, then you don't even have to `require` 306 | anything manually and it should just work out-of-box. 307 | 308 | ### Rake 309 | 310 | Airbrake offers Rake tasks integration, which is used by our Rails 311 | integration[[link](#rails)]. To integrate Airbrake in any project, 312 | just `require` the gem in your `Rakefile`, if it hasn't been required and 313 | [configure][config] the default notifier. 314 | 315 | ```ruby 316 | # Rakefile 317 | require 'airbrake' 318 | 319 | Airbrake.configure do |c| 320 | c.project_id = 113743 321 | c.project_key = 'fd04e13d806a90f96614ad8e529b2822' 322 | end 323 | 324 | task :foo do 325 | 1/0 326 | end 327 | ``` 328 | 329 | ### Plain Ruby scripts 330 | 331 | Airbrake supports _any_ type of Ruby applications including plain Ruby scripts. 332 | If you want to integrate your script with Airbrake, you don't have to use this 333 | gem. The [Airbrake Ruby][airbrake-ruby] gem provides all the needed tooling. 334 | 335 | Deploy tracking 336 | --------------- 337 | 338 | Airbrake has the ability to track your deploys (available only for 339 | [paid plans][pricing]). 340 | 341 | By notifying Airbrake of your application deployments, all errors are resolved 342 | when a deploy occurs, so that you'll be notified again about any errors that 343 | reoccur after a deployment. Additionally, it's possible to review the errors in 344 | Airbrake that occurred before and after a deploy. 345 | 346 | There are several ways to integrate deployment tracking with your application, 347 | that are described below. 348 | 349 | ### Capistrano 350 | 351 | The library supports Capistrano v2 and Capistrano v3. In order to configure 352 | deploy tracking with Capistrano simply `require` our integration from your 353 | Capfile: 354 | 355 | ```ruby 356 | # Capfile 357 | require 'airbrake/capistrano/tasks' 358 | ``` 359 | 360 | If you use Capistrano 3, define the `after :finished` hook, which executes the 361 | deploy notification task (Capistrano 2 doesn't require this step). 362 | 363 | ```ruby 364 | # config/deploy.rb 365 | namespace :deploy do 366 | after :finished, 'airbrake:deploy' 367 | end 368 | ``` 369 | 370 | If you version your application, you can set the `:app_version` variable in 371 | `config/deploy.rb`, so that information will be attached to your deploy. 372 | 373 | ```ruby 374 | # config/deploy.rb 375 | set :app_version, '1.2.3' 376 | ``` 377 | 378 | ### Rake task 379 | 380 | A Rake task can accept several arguments shown in the table below: 381 | 382 | | Key | Required | Default | Example | 383 | ------------|----------|-----------|---------- 384 | ENVIRONMENT | No | Rails.env | production 385 | USERNAME | No | nil | john 386 | REPOSITORY | No | nil | https://github.com/airbrake/airbrake 387 | REVISION | No | nil | 38748467ea579e7ae64f7815452307c9d05e05c5 388 | VERSION | No | nil | v2.0 389 | 390 | #### In Rails 391 | 392 | Simply invoke `rake airbrake:deploy` and pass needed arguments: 393 | 394 | ```bash 395 | rake airbrake:deploy USERNAME=john ENVIRONMENT=production REVISION=38748467 REPOSITORY=https://github.com/airbrake/airbrake 396 | ``` 397 | 398 | #### Anywhere 399 | 400 | Make sure to `require` the library Rake integration in your Rakefile. 401 | 402 | ```ruby 403 | # Rakefile 404 | require 'airbrake/rake/tasks' 405 | ``` 406 | 407 | Then, invoke it like shown in the example for Rails. 408 | 409 | Supported Rubies 410 | ---------------- 411 | 412 | * CRuby >= 1.9.2 413 | * JRuby >= 1.9-mode 414 | * Rubinius >= 2.2.10 415 | 416 | Contact 417 | ------- 418 | 419 | In case you have a problem, question or a bug report, feel free to: 420 | 421 | * [file an issue][issues] 422 | * [send us an email](mailto:support@airbrake.io) 423 | * [tweet at us][twitter] 424 | * chat with us (visit [airbrake.io][airbrake.io] and click on the round orange 425 | button in the bottom right corner) 426 | 427 | License 428 | ------- 429 | 430 | The project uses the MIT License. See LICENSE.md for details. 431 | 432 | Development & testing 433 | --------------------- 434 | 435 | In order to run the test suite, first of all, clone the repo, and install 436 | dependencies with Bundler. 437 | 438 | ```bash 439 | git clone https://github.com/airbrake/airbrake.git 440 | cd airbrake 441 | bundle 442 | ``` 443 | 444 | Next, run unit tests. 445 | 446 | ```bash 447 | bundle exec rake 448 | ``` 449 | 450 | In order to test integrations with frameworks and other libraries, install their 451 | dependencies with help of the following command: 452 | 453 | ```bash 454 | bundle exec appraisal install 455 | ``` 456 | 457 | To run integration tests for a specific framework, use the `appraisal` command. 458 | 459 | ```bash 460 | bundle exec appraisal rails-4.2 rake spec:integration:rails 461 | bundle exec appraisal sinatra rake spec:integration:sinatra 462 | ``` 463 | 464 | Pro tip: [`circle.yml`](/circle.yml) has the list of all integration tests and 465 | commands to invoke them. 466 | 467 | [airbrake.io]: https://airbrake.io 468 | [airbrake-ruby]: https://github.com/airbrake/airbrake-ruby 469 | [issues]: https://github.com/airbrake/airbrake/issues 470 | [twitter]: https://twitter.com/airbrake 471 | [project-idkey]: https://github.com/airbrake/airbrake-ruby#project_id--project_key 472 | [config]: https://github.com/airbrake/airbrake-ruby#config-options 473 | [airbrake-api]: https://github.com/airbrake/airbrake-ruby#api 474 | [rails-runner]: http://guides.rubyonrails.org/command_line.html#rails-runner 475 | [resque-wiki]: https://github.com/resque/resque/wiki/Failure-Backends#using-multiple-failure-backends-at-once 476 | [pricing]: https://airbrake.io/pricing 477 | [heroku-addon]: https://elements.heroku.com/addons/airbrake 478 | [heroku-docs]: https://devcenter.heroku.com/articles/airbrake 479 | [semver]: https://img.shields.io/:semver-5.1.0-brightgreen.svg?style=flat 480 | [migration-guide]: docs/Migration_guide_from_v4_to_v5.md 481 | [dashboard]: https://s3.amazonaws.com/airbrake-github-assets/airbrake/airbrake-dashboard.png 482 | [arthur-ruby]: https://s3.amazonaws.com/airbrake-github-assets/airbrake/arthur-ruby.jpg 483 | -------------------------------------------------------------------------------- /docs/Migration_guide_from_v4_to_v5.md: -------------------------------------------------------------------------------- 1 | Migration guide from v4 to v5 2 | ============================= 3 | 4 | * [Airbrake README](https://github.com/airbrake/airbrake) 5 | * [Airbrake Ruby README](https://github.com/airbrake/airbrake-ruby) 6 | * [YARD API documentation](http://www.rubydoc.info/gems/airbrake-ruby) 7 | 8 | The Airbrake gem v5 release introduced [new 9 | features](https://github.com/airbrake/airbrake/blob/master/CHANGELOG.md#v500), 10 | bug fixes and some breaking changes. Don't worry, we tried to make this 11 | transition as smooth as possible. This guide will help you to upgrade from 12 | Airbrake v4 to Airbrake v5. 13 | 14 | The most prominent change is that the Airbrake gem was split into two gems: 15 | `airbrake` and `airbrake-ruby`. The `airbrake-ruby` gem is the core gem, which 16 | defines how to send notices. The `airbrake` gem contains integrations with web 17 | frameworks and other software. 18 | 19 | Please note, that we still _do support_ Airbrake v4 for quite some 20 | time. However, it is _feature frozen_. 21 | 22 | Migration Instructions 23 | ---------------------- 24 | 25 | * [General changes](#general-changes) 26 | * [Configuration](#configuration) 27 | * [Library API](#library-api) 28 | * [Other changes](#other-changes) 29 | * [Integration changes](#integration-changes) 30 | * [Heroku](#heroku) 31 | * [Rails](#rails) 32 | * [Rack applications](#rack-applications) 33 | * [Resque](#resque) 34 | * [Sidekiq](#sidekiq) 35 | * [Deployment with Rake task](#deployment-with-rake-task) 36 | * [Capistrano](#capistrano) 37 | 38 | ### General changes 39 | 40 | #### Configuration 41 | 42 | Old option | New option | required? 43 | ---|---|--- 44 | api_key | [project_key](#api-key) | required 45 | n/a | [project_id](#project-id) | required 46 | development_environments | [ignore_environments](#development-environments) | optional 47 | port | [host](#port) | optional 48 | secure | [host](#secure) | optional 49 | proxy_host | [proxy](#proxy)| optional 50 | proxy_port | [proxy](#proxy)| optional 51 | proxy_user | [proxy](#proxy)| optional 52 | proxy_pass | [proxy](#proxy)| optional 53 | params_filter | [add_filter](#filtering) | optional 54 | params_whitelist_filter | [add_filter](#filtering) | optional 55 | backtrace_filters | [add_filter](#filtering) | optional 56 | ignore_by_filters | [add_filter](#filtering) | optional 57 | rake_environment_filters | [add_filter](#filtering) | optional 58 | ignore | [add_filter](#filtering) | optional 59 | ignore_rake | [add_filter](#filtering) | optional 60 | ignore_user_agent | [add_filter](#filtering) | optional 61 | environment_name | [environment](#environment-name) | optional 62 | project_root | [root_directory](#project-root) | optional 63 | async | removed ([async by default](#notify)) | n/a 64 | http_open_timeout | removed | n/a 65 | development_lookup | removed | n/a 66 | notifier_name | removed | n/a 67 | notifier_url | removed | n/a 68 | notifier_version | removed | n/a 69 | user_information | removed | n/a 70 | framework | removed | n/a 71 | rescue_rake_exceptions | removed | n/a 72 | user_attributes | removed | n/a 73 | test_mode | removed | n/a 74 | 75 | * 76 | The `api_key` option was renamed to `project_key`. 77 | [[link](#api-key)] 78 | 79 | ```ruby 80 | # Old way 81 | Airbrake.configure do |c| 82 | c.api_key = 'a1b2c3d4e5f6g780' 83 | end 84 | 85 | # New way 86 | Airbrake.configure do |c| 87 | c.project_key = 'a1b2c3d4e5f6g780' 88 | end 89 | ``` 90 | 91 | * 92 | The new mandatory option - `project_id`. To find your project's id, either 93 | copy it from the URL or navigate to your project's settings and find these 94 | fields on the right sidebar. 95 | [[link](#project-id)] 96 | 97 | ![][project-idkey] 98 | 99 | ```ruby 100 | # Old way 101 | # Didn't exist. 102 | 103 | # New way 104 | Airbrake.configure do |c| 105 | c.project_id = 93597 106 | end 107 | ``` 108 | 109 | * 110 | The `development_environments` option was renamed to `ignore_environments`. 111 | Its behaviour was also slightly changed. By default, the library sends 112 | exceptions in _all_ environments, so you don't need to assign an empty Array 113 | anymore to get this behavior. If you relied on the default value of 114 | `development_environments` before upgrading, you should explicitly set 115 | `ignore_environments` to `%w(development test cucumber)` to preserve the old 116 | behavior. 117 | [[link](#development-environments)] 118 | 119 | ```ruby 120 | # Old way 121 | Airbrake.configure do |c| 122 | c.development_environments = %w(development test) 123 | 124 | # OR to collect exceptions in all envs 125 | 126 | c.development_environments = [] 127 | 128 | # OR don't set this option to get the default (development, test, cucumber) 129 | end 130 | 131 | # New way 132 | Airbrake.configure do |c| 133 | c.environment = Rails.env 134 | c.ignore_environments = %w(development test) 135 | 136 | # OR to collection exceptions in all envs 137 | 138 | # Simply don't set this option 139 | 140 | # OR use the old default value 141 | 142 | c.ignore_environments = %w(development test cucumber) 143 | end 144 | ``` 145 | 146 | * 147 | The `port` option was removed. It was merged with the `host` option. From now 148 | on simply include your port in your host. 149 | [[link](#port)] 150 | 151 | ```ruby 152 | # Old way 153 | Airbrake.configure do |c| 154 | c.host = 'example.com' 155 | c.port = 8080 156 | end 157 | 158 | # New way 159 | Airbrake.configure do |c| 160 | c.host = 'http://example.com:8080' 161 | end 162 | ``` 163 | 164 | * 165 | The `secure` option was removed. It was merged with the `host` option. From 166 | now on simply specify your protocol, when you define `host`. The library will 167 | guess the mode based on the URL scheme (HTTP or HTTPS). 168 | [[link](#secure)] 169 | 170 | ```ruby 171 | # Old way 172 | Airbrake.configure do |c| 173 | c.host = 'example.com' 174 | c.secure = true 175 | end 176 | 177 | # New way 178 | Airbrake.configure do |c| 179 | c.host = 'https://example.com' 180 | end 181 | ``` 182 | 183 | * 184 | The `http_open_timeout` & `http_read_timeout` options were removed. 185 | [[link](#http-open-timeout)] 186 | 187 | * 188 | The `proxy_host`, `proxy_port`, `proxy_user` & `proxy_pass` options were 189 | merged into one option - `proxy`. It accepts a Hash with the `host`, `port`, 190 | `user` & `password` keys. 191 | [[link](#proxy)] 192 | 193 | ```ruby 194 | # Old way 195 | Airbrake.configure do |c| 196 | c.proxy_host = 'example.com' 197 | c.proxy_port = 8080 198 | c.proxy_user = 'user' 199 | c.proxy_pass = 'p4ssw0rd' 200 | end 201 | 202 | # New way 203 | Airbrake.configure do |c| 204 | c.proxy = { 205 | host: 'example.com' 206 | port: 8080 207 | user: 'user' 208 | password: 'p4ssw0rd' 209 | } 210 | end 211 | ``` 212 | 213 | * 214 | The `params_filters` option was replaced with the 215 | [blacklist filter](#blacklist-filter). 216 | [[link](#params-filters)] 217 | 218 | * 219 | The `params_whitelist_filters` option was replaced with the [whitelist 220 | filter](#whitelist-filter) 221 | [[link](#whitelist-filter)] 222 | 223 | * 224 | The `backtrace_filters`, `ignore_by_filters`, `rake_environment_filters`, 225 | `ignore`, `ignore_rake` & `ignore_user_agent` option were replaced with the 226 | [`add_filter` API](#ignore-by-filter). 227 | [[link](#filtering)] 228 | 229 | * 230 | The `development_lookup` option was removed. 231 | [[link](#development-lookup)] 232 | 233 | * 234 | The `environment_name` was renamed to `environment`. 235 | [[link](#environment-name)] 236 | 237 | ```ruby 238 | # Old way 239 | Airbrake.configure do |c| 240 | c.environment_name = 'staging' 241 | end 242 | 243 | # New way 244 | Airbrake.configure do |c| 245 | c.environment = 'staging' 246 | end 247 | ``` 248 | 249 | * 250 | The `project_root` option was renamed to `root_directory`. 251 | [[link](#project-root)] 252 | 253 | NOTE: you *must* set this if you want Airbrake backtraces to link to 254 | GitHub. In Rails projects this value should typically be equal to 255 | `Rails.root`. 256 | 257 | ```ruby 258 | # Old way 259 | Airbrake.configure do |c| 260 | c.project_root = '/var/www/project' 261 | end 262 | 263 | # New way 264 | Airbrake.configure do |c| 265 | c.root_directory = '/var/www/project' 266 | end 267 | ``` 268 | 269 | * 270 | The `notifier_name`, `notifier_url` & `notifier_version` options were removed. 271 | [[link](#notifier-name)] 272 | 273 | * 274 | The `user_information` option was removed. 275 | [[link](#user-information)] 276 | 277 | * 278 | The `framework` option was removed. 279 | [[link](#framework)] 280 | 281 | * 282 | The `rescue_rake_exceptions` option was removed. 283 | [[link](#rescue-rake)] 284 | 285 | * 286 | The `user_attributes` option was removed. 287 | [[link](#user-attributes)] 288 | 289 | * 290 | The `test_mode` option was removed. 291 | [[link](#test-mode)] 292 | 293 | * 294 | The `async` option was removed. Airbrake is now async by default. 295 | Read the [`Airbrake.notify` docs](#airbrake-notify) for more information. 296 | [[link](#async)] 297 | 298 | * 299 | The list of default ignored exceptions was relaxed. The library now ignores 300 | only `SystemExit` exceptions. 301 | [[link](#default-ignored-classes)] 302 | 303 | #### Library API 304 | 305 | ##### Blacklist filter 306 | 307 | Instead of [various filter options](#params-filters) the library supports 308 | blacklist filtering. The blacklist filter is global, which means it filters 309 | every matching key in the notice's payload. 310 | 311 | ```ruby 312 | # Old way 313 | Airbrake.configure do |c| 314 | c.params_filters << 'credit_card_number' 315 | end 316 | 317 | # New way 318 | Airbrake.blacklist_keys([:credit_card_number]) 319 | ``` 320 | 321 | ##### Whitelist filter 322 | 323 | Instead of [various filter options](#params-whitelist-filters) the library 324 | supports whitelist filtering. The whitelist filter is global, which means it 325 | filters every key except the specified ones. 326 | 327 | ```ruby 328 | # Old way 329 | Airbrake.configure do |c| 330 | c.params_whitelist_filters << 'email' 331 | end 332 | 333 | # New way 334 | Airbrake.whitelist_keys([:email]) 335 | ``` 336 | 337 | ##### Ignore by filter 338 | 339 | Since the `ignore_by_filter` option was removed, the new API was introduced - 340 | `Airbrake.add_filter`. The API is similar to `ignore_by_filter`, but 341 | `.add_filter` doesn't rely on return values. Instead, you can mark notices as 342 | ignored with help of the `Airbrake::Notice#ignore!` method. `Airbrake.add_filter` 343 | replaces a lot of [legacy options](#filtering). 344 | 345 | ```ruby 346 | # Old way 347 | Airbrake.configure do |c| 348 | c.ignore_by_filter do |exception_data| 349 | true if exception_data[:error_class] == "RuntimeError" 350 | end 351 | end 352 | 353 | # New way 354 | Airbrake.add_filter do |notice| 355 | # The library supports nested exceptions, so one notice can carry several 356 | # exceptions. 357 | if notice[:errors].any? { |error| error[:type] == 'RuntimeError' } 358 | notice.ignore! 359 | end 360 | end 361 | ``` 362 | 363 | The `notice` that `add_filter` yields is an instance of `Airbrake::Notice`. Its 364 | public API is [described in the `airbrake-ruby` 365 | README](https://github.com/airbrake/airbrake-ruby#notice). 366 | 367 | ##### Notify 368 | 369 | * 370 | `Airbrake.notify` is now async. To be able to send exceptions synchronously, 371 | the `Airbrake.notify_sync` method was added. Both methods have the same 372 | method signature. 373 | [[link](#airbrake-notify)] 374 | 375 | The list of accepted arguments was amended. The first argument can now 376 | additionally accept Strings. The second argument is still a Hash, but the 377 | difference is that anything you pass there will be added to the Params tab. 378 | The support for `api_key`, `error_message`, `backtrace`, `parameters` and 379 | `session` was removed. 380 | 381 | ```ruby 382 | # Old way 383 | Airbrake.notify( 384 | RuntimeError.new('Oops'), 385 | api_key: '1a2b3c4d5e6f7890', 386 | error_message: 'Notification', 387 | backtrace: caller, 388 | parameters: {}, 389 | session: {} 390 | ) 391 | 392 | # New way 393 | Airbrake.notify('Oops', this_will_be: 'prepended to the Params tab') 394 | ``` 395 | 396 | * 397 | `Airbrake.notify_or_ignore` was removed. 398 | [[link](#notify-or-ignore)] 399 | 400 | #### Other changes 401 | 402 | * 403 | The library no longer sends `ENV` by default. If you need this behaviour, 404 | use the [`add_filter` API](#ignore-by-filter). 405 | [[link](#env)] 406 | 407 | ```ruby 408 | Airbrake.add_filter do |notice| 409 | notice[:environment].merge!(ENV) 410 | end 411 | ``` 412 | 413 | * 414 | The `Airbrake.configuration` interface was removed. It's no longer possible 415 | to read config values. 416 | [[link](#airbrake-configuration)] 417 | 418 | * 419 | The Airbrake CLI was removed completely. Instead, it is recommended to use 420 | [Rake tasks](#deployment-with-rake-task). 421 | [[link](#cli)] 422 | 423 | * 424 | The bundled `ca-bundle.crt` was removed. 425 | [[link](#ca-cert)] 426 | 427 | ### Integration changes 428 | 429 | #### Heroku 430 | 431 | * 432 | The deploy hook Rake task was renamed from 433 | `airbrake:heroku:add_deploy_notification` to 434 | `airbrake:install_heroku_deploy_hook`. 435 | [[link](#heroku-deploy-hook)] 436 | 437 | ```shell 438 | # Old way 439 | bundle exec rake airbrake:heroku:add_deploy_notification 440 | 441 | # New way 442 | bundle exec rake airbrake:install_heroku_deploy_hook 443 | ``` 444 | 445 | * 446 | The way to generate the Airbrake config was simplified. 447 | [[link](#heroku-generator)] 448 | 449 | ```ruby 450 | # Old way 451 | rails g airbrake --api-key `heroku config:get AIRBRAKE_API_KEY` 452 | 453 | # New way 454 | rails g airbrake 455 | ``` 456 | 457 | #### Rails 458 | 459 | * 460 | The support for Rails 2 was dropped. Airbrake v5 officially supports only 461 | `3.2.*`, `4.0.*`, `4.1.*`, `4.2.*` and above. 462 | [[link](#rails-2-support)] 463 | 464 | * 465 | The Rails generator was changed to accept two parameters: project id and 466 | project key. The `--api-key` flag was removed. 467 | [[link](#rails-generator)] 468 | 469 | ```ruby 470 | # Old way 471 | rails g airbrake --api-key YOUR_API_KEY 472 | 473 | # New way 474 | rails g airbrake YOUR_PROJECT_ID YOUR_API_KEY 475 | ``` 476 | 477 | * 478 | The `notify_airbrake` helper method's signature was amended to conform to the 479 | [`Airbrake.notify`](#airbrake-notify) signature. 480 | [[link](#rails-notify)] 481 | 482 | #### Rack applications 483 | 484 | The name of the Airbrake Rack middle ware was changed from 485 | `Airbrake::Rails::Middleware` to `Airbrake::Rack::Middleware` 486 | 487 | ```ruby 488 | # Old way 489 | use Airbrake::Rails::Middleware 490 | 491 | # New way 492 | use Airbrake::Rack::Middleware 493 | ``` 494 | 495 | #### Resque 496 | 497 | Replace `resque/failure/airbrake` with `airbrake/resque/failure` 498 | 499 | ```ruby 500 | # Old way 501 | require 'resque/failure/airbrake' 502 | Resque::Failure.backend = Resque::Failure::Airbrake 503 | 504 | # New way 505 | require 'airbrake/resque/failure' 506 | Resque::Failure.backend = Resque::Failure::Airbrake 507 | ``` 508 | 509 | #### Sidekiq 510 | 511 | Replace `airbrake/sidekiq` with `airbrake/sidekiq/error_handler` 512 | 513 | ```ruby 514 | # Old way 515 | require 'airbrake/sidekiq' 516 | 517 | # New way 518 | require 'airbrake/sidekiq/error_handler' 519 | ``` 520 | 521 | #### Deployment with Rake task 522 | 523 | The list of recognised environment variables passed to the `airbrake:deploy` 524 | Rake task was changed. 525 | 526 | ```shell 527 | # Old way 528 | rake airbrake:deploy USER=john TO=production REVISION=38748467 REPO=https://github.com/airbrake/airbrake 529 | 530 | # New way 531 | rake airbrake:deploy USERNAME=john ENVIRONMENT=production REVISION=38748467 REPOSITORY=https://github.com/airbrake/airbrake 532 | ``` 533 | 534 | #### Capistrano 535 | 536 | There is no longer a difference between integration with Capistrano 2 and 3. For 537 | Capistrano 3 you no longer need an `after` hook. 538 | 539 | ```ruby 540 | # Old way 541 | # For Capistrano 2 542 | # Capfile 543 | require 'airbrake/capistrano' 544 | # For Capistrano 3 545 | # Capfile 546 | require 'airbrake/capistrano3' 547 | # config/deploy.rb 548 | after 'deploy:finished', 'airbrake:deploy' 549 | 550 | # New way 551 | # For Capistrano 2 552 | require 'airbrake/capistrano/tasks' 553 | # For Capistrano 3 554 | # Capfile 555 | require 'airbrake/capistrano/tasks' 556 | # config/deploy.rb 557 | after :finished, 'airbrake:deploy' 558 | ``` 559 | 560 |
561 | 562 |
563 | Happy Airbraking with Airbrake v5! 564 |
565 | The Airbrake team 566 |
567 | 568 | [project-idkey]: https://img-fotki.yandex.ru/get/3907/98991937.1f/0_b558a_c9274e4d_orig 569 | -------------------------------------------------------------------------------- /docs/CHANGELOG-pre-v5.txt: -------------------------------------------------------------------------------- 1 | Version 4.3.1 - 2015-08-24 21:10:19 -0500 2 | =============================================================================== 3 | 4 | Edoardo Rossi (1): 5 | Fix missing api_key when using V3 endpoint URL 6 | 7 | Igor Kapkov (2): 8 | Use getters instead of handwriten methods 9 | Update readme to fix appraisal deprecation 10 | 11 | Kyrylo Silin (5): 12 | Merge pull request #404 from zeroed/master 13 | Merge pull request #405 from igas/little-optimization 14 | Merge pull request #408 from igas/update-readme-to-fix-appraisal-deprecation 15 | Merge pull request #406 from Aupajo/fix/ambiguous-rails 16 | Merge pull request #403 from lisovskyvlad/master 17 | 18 | Lisovsky Vlad (1): 19 | Fix dumping notice object to xml for rails 2.3.10 and builder 2.1.2 20 | 21 | Mark Nadig (1): 22 | capistrano task should handle symbols for env 23 | 24 | Pete Nicholls (1): 25 | Use ::Rails namespace for Rails::VERSION 26 | 27 | shifi (3): 28 | Merge branch 'issue_393' of https://github.com/KonaTeam/airbrake into KonaTeam-issue_393 29 | Merge branch 'KonaTeam-issue_393' 30 | add guidelines for contributing 31 | 32 | 33 | Version 4.3.0 - 2015-06-23 19:36:10 -0500 34 | =============================================================================== 35 | 36 | Omer Gazit (1): 37 | Add ability to define whitelist filters for parameters 38 | 39 | shifi (7): 40 | use top level namespace and stay compatible with Rails 2.x - fixes #388 41 | update to match new changes 42 | support whitelist and blacklist approach for params filters and support nested filter arrays 43 | add more tests for params cleaner 44 | Merge branch 'feature/whitelist-params-filters' 45 | add HTTP_AUTHORIZATION to rack filters 46 | make sure we remove all sensitive rack vars 47 | 48 | 49 | Version 4.2.1 - 2015-06-01 22:12:49 -0500 50 | =============================================================================== 51 | 52 | Marko Šiftar (3): 53 | Merge pull request #384 from biske/improve-notify-documentation 54 | Merge pull request #385 from arrtchiu/patch-2 55 | Merge pull request #386 from airbrake/fix/check-if-failsafe-middleware-is-defined 56 | 57 | Phuong Nguyen (1): 58 | Insert UserInformer middleware before Rack::Runtime since Rack::Lock may not be available for app with websocket-rails 59 | 60 | arrtchiu (1): 61 | Support Rails 4 without ActiveRecord 62 | 63 | shifi (7): 64 | typo in changelog 65 | add more args in deploy CLI - fixes #296 66 | update CLI help info 67 | do not require pry - fix typo 68 | check if failsafe middleware is defined - fixes #379 69 | fix conflicts 70 | Merge branch 'phuongnd08-master' 71 | 72 | Иван Бишевац (1): 73 | Improves documentation for notify method 74 | 75 | 76 | Version 4.2.0 - 2015-05-27 19:05:32 -0500 77 | =============================================================================== 78 | 79 | Abdelkader Boudih (1): 80 | Update sidekiq.rb 81 | 82 | Adam King (1): 83 | Fix DEFAULT_BACKTRACE_FILTERS bug that caused backtrace to not show up in certain contexts. See https://github.com/airbrake/airbrake/issues/343. 84 | 85 | David (8): 86 | Merge pull request #329 from grosser/grosser/gemspec 87 | Merge pull request #335 from airbrake/fix/cucumber-suite 88 | Merge pull request #327 from airbrake/feature/faster-params-cleaning 89 | Merge pull request #337 from airbrake/fix/rails4-is-here 90 | Merge pull request #326 from airbrake/fix/cast-ENV-to-Hash 91 | Merge pull request #328 from grosser/grosser/dup 92 | Merge pull request #334 from airbrake/fix/user-info-consumes-db-connections 93 | Merge pull request #340 from grosser/grosser/dup 94 | 95 | David Palm (9): 96 | Cast CGI data to hash, as that's what the code really expects 97 | Speed up notice generation by avoiding copying data and putting most common cases on top 98 | Refactor #airbrake_current_user 99 | Typo 100 | Add comment explaining why we release connections 101 | Comment out @wip scenarios to facilitate running parts of the suite 102 | Add 4 to version sniffing code 103 | PR feedback 104 | Clone to ensure we do not mess with the provided data 105 | 106 | Eero Raun (1): 107 | Ignore RACK_ENV if it is empty (capistrano deploy), fixes #341. 108 | 109 | Jonathan Worek (1): 110 | Assumption of existence of :app role may not be valid 111 | 112 | Marko Šiftar (3): 113 | Merge pull request #354 from wojobucco/patch-1 114 | Merge pull request #342 from oree/341 115 | Merge pull request #382 from airbrake/fix/use-proper-capistrano-hook 116 | 117 | Martin Tepper (1): 118 | This should fix #369 119 | 120 | grosser (3): 121 | cleanup gemspec 122 | fix having symbols in the environment blows up filter_parameters with blocks 123 | If we cannot stringify then at least rescue the dup exceptions ... 124 | 125 | halida (1): 126 | fix rails request.fullpath behavior change in 4.1.6 -- no longer has leading / 127 | 128 | shifi (16): 129 | add test for filtering frozen objects 130 | Merge branch 'Promptus-issue_369_frozen_array_issue' 131 | update Appraisals file 132 | Merge branch 'master' of https://github.com/halida/airbrake into halida-master 133 | remove whitespaces 134 | add test for airbrake_request_url 135 | Merge branch 'halida-master' 136 | update year in license and readme 137 | use proper capistrano hook depending on capistrano version 138 | set localhost IP to satisfy web console when testing in development 139 | Merge branch 'patch-1' of https://github.com/seuros/airbrake into seuros-patch-1 140 | fix syntax error in Sidekiq configuration 141 | Merge branch 'seuros-patch-1' 142 | Merge branch 'master' of https://github.com/developwithvelocity/airbrake into developwithvelocity-master 143 | tests for backtrace default filters - gem paths 144 | Merge branch 'developwithvelocity-master' 145 | 146 | 147 | Version 4.1.0 - 2014-09-04 23:16:08 +0200 148 | =============================================================================== 149 | 150 | Benjamin Fleischer (1): 151 | Add license to gemspec, is MIT 152 | 153 | Chun-wei Kuo (1): 154 | Add missing RAILS_ENV to the deploy notification task for Capistrano 3 155 | 156 | David (1): 157 | Merge pull request #306 from kiela/master 158 | 159 | Giovanni Cappellotto (1): 160 | Add support for Sidekiq > 3 161 | 162 | Kamil Kieliszczyk (2): 163 | Add ability to filter arrays 164 | Add ability to filter arrays 165 | 166 | Kelley Reynolds (1): 167 | Ignore ActionController::UnknownFormat for Rails 4+ which is now handled by middleware 168 | 169 | Marko Šiftar (11): 170 | Revert "Add ability to filter arrays" 171 | Merge pull request #307 from airbrake/revert-306-master 172 | Merge pull request #305 from Domon/fix-capistrano3-task 173 | Merge pull request #302 from gregory/remove_unused_controller 174 | Merge pull request #310 from kiela/master 175 | Merge pull request #271 from rykov/master 176 | Merge pull request #275 from kreynolds/rails-4-unknown-format 177 | Merge pull request #312 from bf4/add_license_to_gemspe 178 | Merge pull request #304 from pitchtarget/sidekiq-support 179 | Merge pull request #273 from meetme2meat/master 180 | Merge pull request #300 from chute/master 181 | 182 | Michael Rykov (1): 183 | Keep passed exception if original_exception is nil 184 | 185 | Petr Bela (1): 186 | Add RACK_ENV to rake task for non-Rails apps 187 | 188 | Sami Haahtinen (1): 189 | Update capistrano v3 support 190 | 191 | Viren Negi (1): 192 | Added a comment to how to add specify environment when use with rack app 193 | 194 | gregory (1): 195 | remove unused controller 196 | 197 | shifi (4): 198 | update capistrano test to make sure we set RAILS_ENV when using rake task 199 | Update ignored exceptions by default in Readme 200 | fix conflicts in airbrake.cap 201 | Merge branch 'ressu-capistrano3' 202 | 203 | 204 | Version 4.0.0 - 2014-05-27 16:32:26 -0700 205 | =============================================================================== 206 | 207 | Ali Faiz (2): 208 | Remove the Airbrake JS notifier for the major release. 209 | 210 | 211 | Version 3.2.1 - 2014-05-27 15:58:24 -0700 212 | =============================================================================== 213 | 214 | Ali Faiz (3): 215 | Revert "Merge pull request #297 from airbrake/remove-js-notifier" 216 | Add deprecation warning when using . 217 | 218 | 219 | Version 3.2.0 - 2014-05-23 17:37:35 -0700 220 | =============================================================================== 221 | 222 | Ali Faiz (4): 223 | Remove JS notifier from templates and libraries 224 | Cleanup references to JS notifier in tests 225 | Merge pull request #297 from airbrake/remove-js-notifier 226 | 227 | 228 | Version 3.1.17 - 2014-05-20 21:00:25 -0700 229 | =============================================================================== 230 | 231 | Alex Tomlins (1): 232 | Only send notices if configured with api_key 233 | 234 | Ali Faiz (22): 235 | Add tasks specific for using appraisal to test different versions 236 | Ensure that integration tests can use the same helpers as unit tests 237 | Fix errors causing features to fail 238 | Add sqlite3 for Rails 3.2 & 4.0 appraisal gems 239 | Fix integrations with Rails 3.0 by locking sucker_punch to v1.0.2. 240 | Update README.md 241 | Merge pull request #285 from airbrake/adjust-ci-integration 242 | Merge pull request #281 from jhawthorn/fix_actioncontroller_metal 243 | Merge pull request #268 from alphagov/disable_unless_configured 244 | Merge pull request #287 from itolmach/master 245 | Add apikey to certain cucumber tests for changes for configured 246 | Merge pull request #288 from airbrake/fix-apikey-related-tests 247 | Merge pull request #277 from polleverywhere/rails3_filter_parameters 248 | Merge pull request #262 from roqua/mv-regex-filters 249 | Fix filtering checks in cucumber tests by checking for 'key=' instead of blind check 250 | Make separate step for the cucumber test that checks for filtered keys 251 | Merge pull request #289 from airbrake/fix-regex-filtering 252 | Write verbose output when configuration prevents sending notices to Airbrake. 253 | Merge pull request #294 from Nitrodist/ensure-rake-integration 254 | Merge pull request #295 from airbrake/add-context-when-notice-not-sent 255 | Merge pull request #293 from Nitrodist/use-minitest-4 256 | Use tag date instead of trying to sort on tag name 257 | 258 | Ivan Tolmachev (3): 259 | added airbrakeman notifier ruby illustration 260 | illustration added, take 2 261 | Added Airbrakeman Notifier Illustration 262 | 263 | John Hawthorn (1): 264 | fix middleware for AC::Metal on rails 3.2 265 | 266 | Version 3.1.16 - 2014-03-11 13:34:51 -0700 267 | =============================================================================== 268 | 269 | Joseph Silvashy (5): 270 | Merge pull request #267 from nberger/fix-typo-in-rails3-tasks 271 | Update license for Rackspace 272 | Merge pull request #255 from viperdezigns/capistrano3 273 | Bump to 3.1.14 274 | Bump to 3.1.16 275 | 276 | Mark Campbell (2): 277 | Add minitest 4.x as an explicit dependency 278 | Ensure rake integration is enabled when rescue_rake_exceptions is true 279 | 280 | Marten Veldthuis (3): 281 | Add support for regexp filters 282 | Refactor cgi_data filtering to use `filter_key?` 283 | Add a default rack env filter for variables matching "secret" or "password". 284 | 285 | Mike Foley (2): 286 | Add backwards compatibility for filter_parameters in Rails3 287 | Add tests, minor refactor for Rails 3 functionality 288 | 289 | Nicolas Berger (1): 290 | Fix typo: Rack -> Rake 291 | 292 | Richard Pernikoff (3): 293 | execute instead of run 294 | get full revision hash and send correct repo url 295 | execute the rake task within the release_path instead of running cd release_path. 296 | 297 | ViperDezigns (1): 298 | Merge pull request #2 from tunespeak/capistrano3 299 | 300 | spodlecki (7): 301 | adding capistrano 3 302 | attempting err fixes 303 | release_path 304 | making repo name a env var 305 | adding airbrake escape user method 306 | logger.info doesn't exist, seems Cap uses info() now 307 | execute instead of run 308 | 309 | 310 | Version 3.1.15 - 2014-01-03 14:37:38 +0100 311 | =============================================================================== 312 | 313 | Ahmad Sherif (1): 314 | Don't serialize nil to an empty string 315 | 316 | Damon Morgan (1): 317 | Support sucker_punch for async processor 318 | 319 | David Palm (1): 320 | Give params_filter a setter so it can be *set* (not only appended to) 321 | 322 | Hrvoje Šimić (14): 323 | add Rails 4 to README.md 324 | use Coveralls for code coverage 325 | use Gemnasium for dependency monitoring 326 | use Code Climate for code analysis 327 | extract ParamsCleaner class 328 | being more careful with javascript_notifier and non-public requests 329 | Bumping to version 3.1.14 330 | add Circle CI badge 331 | rename :test task to 'test:unit' 332 | use parallel gem installation on CI server 333 | enable pry debugging in tests 334 | add test for #251 335 | enable filtering of sensitive Rack vars by default 336 | start using MultiJson 337 | 338 | Marko Šiftar (1): 339 | fix deploy uri 340 | 341 | Marten Veldthuis (1): 342 | Airbrake rakefile is not compatible with Capistrano v3 343 | 344 | Rodrigo Saito (1): 345 | Handle error when variable sinatra.error is present 346 | 347 | 348 | Version 3.1.14 - 2013-08-22 09:03:14 +0200 349 | =============================================================================== 350 | 351 | Hrvoje Šimić (5): 352 | use Coveralls for code coverage 353 | use Gemnasium for dependency monitoring 354 | use Code Climate for code analysis 355 | extract ParamsCleaner class 356 | being more careful with javascript_notifier and non-public requests 357 | 358 | 359 | Version 3.1.13 - 2013-08-20 09:39:41 +0200 360 | =============================================================================== 361 | 362 | Anton Minin (1): 363 | Fix notice crash on empty cgi_data 364 | 365 | Cedric Brancourt (2): 366 | fixes #231 When no session in controller , airbrake_session_data returns {:session => "no session found"} 367 | fixes airbrake/airbrake#233 duplicate cgi_data in Notice params 368 | 369 | Chris Gunther (2): 370 | Coerce user attributes to strings before checking that they are valid. 371 | Reject invalid user attributes on assignment 372 | 373 | Hongli Lai (Phusion) (1): 374 | Add support for SSL in the command line tool. 375 | 376 | Hrvoje Šimić (22): 377 | better explanation of ignored environments and classes 378 | add test for warnings about user attributes 379 | remove unnecessary active record requirements 380 | remove platform checks from nil logger initialization 381 | update bourne dependency to fix test-running issues with ruby 2.0.0 382 | test against ruby 2.0.0 on a CI server 383 | remove mocha deprecation warnings 384 | be more careful when reading sinatra environment name 385 | wrap the js configuration in try-catch 386 | ignore Gemfile.lock 387 | lock json-schema to 1.0.12 388 | add a scenario for ignoring rake exceptions [#223] 389 | get rid of activesupport once and for all 390 | fully support Rails 4.0 391 | stop using appraisals for unit tests 392 | fix formatting of airbrake_session_data 393 | fix test for no session controller [#232] 394 | include actionpack and activesupport in gemspec for tests 395 | cleaning up tests 396 | cleaning the codebase from warnings issued in ruby verbose mode 397 | remove private writers and use instance variables to remove warnings 398 | fixing changeling's version sorting 399 | 400 | Jason Petersen (1): 401 | Escape user name in Airbrake notify command 402 | 403 | Konstantin Zub (1): 404 | return environment_info unless environment_name 405 | 406 | Kris Kemper (1): 407 | Allow backtrace to be a String 408 | 409 | Nathan Broadbent (1): 410 | Use a separate (blank) array of ignored exceptions for Rake tasks 411 | 412 | Subhash Chandra (1): 413 | split javascript notifier into loader and configuration 414 | 415 | Tony Spore (1): 416 | use 'bundle exec' in capistrano task 417 | 418 | 419 | Version 3.1.12 - 2013-04-29 18:48:40 +0200 420 | =============================================================================== 421 | 422 | Arvind Kunday (1): 423 | Removing the .erb template handler 424 | 425 | Hrvoje Šimić (8): 426 | introducing null logger for fallback 427 | add missing logger requirement 428 | being careful with silencing of rake backtrace in the airbrake:test task 429 | support for Rails 4.0 430 | start using remote XSD file when verifying XML in tests 431 | throw a warning for unsupported user attributes 432 | updating outdated step definition for current user feature 433 | speeding up the test by using 'runner' instead of 'server' 434 | 435 | knapo (1): 436 | Fix Airbrake::Sender#log to log messages when logger is not passed to options. 437 | 438 | 439 | Version 3.1.11 - 2013-04-11 12:44:09 +0200 440 | =============================================================================== 441 | 442 | Eric Jensen (1): 443 | add --scm-revision option to cli 444 | 445 | Hrvoje Šimić (10): 446 | update tested rails versions 447 | reverting parts of 8768b1 that caused broken XML 448 | update integration test 449 | stop cluttering STDERR from rake airbrake:test 450 | test coverage for Airbrake::Response 451 | introduce configurable test mode 452 | add the test mode option to the generator 453 | update the test suite to use the test mode accordingly 454 | stop using the 'progress' format when running features 455 | fix defaults in integration test 456 | 457 | Kenneth Kalmer (2): 458 | Wrap the JS notifier configuration in a try..catch, since the notifier JS might have failed to load 459 | Set a noop window.onerror in the event Airbrake is not available 460 | 461 | Mark J. Titorenko (1): 462 | Use env rather than @env when constructing fallback request data. 463 | 464 | Marko Šiftar (1): 465 | pretty formatting of notice details 466 | 467 | 468 | Version 3.1.10 - 2013-04-03 15:41:13 +0200 469 | =============================================================================== 470 | 471 | Mark J. Titorenko (1): 472 | Use env rather than @env when constructing fallback request data. 473 | 474 | 475 | Version 3.1.9 - 2013-03-25 20:06:10 +0100 476 | =============================================================================== 477 | 478 | Bartosz Knapik (2): 479 | .rbenv-version should be in gitignore 480 | replace current_release with release_path 481 | 482 | Chas Lemley (1): 483 | correctly use config.user_attributes= 484 | 485 | Hrvoje Šimić (6): 486 | Update year in README 487 | thread safety fix 488 | add the secure option to the generator 489 | fix the broken generator method call 490 | be more careful with @template in javascript notifier 491 | update tested rails versions 492 | 493 | Marko Šiftar (2): 494 | just collect id by default 495 | update test suite (user details) 496 | 497 | Robert Glaser (1): 498 | log failed certicate verifications 499 | 500 | Thilo-Alexander Ginkel (1): 501 | Partial thread-safety fix 502 | 503 | Thom Mahoney (1): 504 | Airbake::Backtrace::Line#method => #method_name 505 | 506 | jokerswanted (1): 507 | Update README.md 508 | 509 | 510 | Version 3.1.8 - 2013-02-05 16:29:43 +0100 511 | =============================================================================== 512 | 513 | Hrvoje Šimić (5): 514 | rename SUPPORTED_RAILS_VERSIONS to TESTED_AGAINST 515 | don't call id on nil - fixes #177 516 | move our middleware right after exception middleware (#178) 517 | implement tests for #178 518 | be nice to older rails versions 519 | 520 | 521 | Version 3.1.7 - 2013-01-28 13:35:10 +0100 522 | =============================================================================== 523 | 524 | Adam Duke (1): 525 | fix an error if not using ActionController::Base 526 | 527 | Ben Arent (2): 528 | Update to Readme.md 529 | 2013! woot. 530 | 531 | Cory Kaufman-Schofield (1): 532 | Use https for rake airbrake:test if force_ssl set to true (fixes #145) 533 | 534 | Dmitry Medvinsky (1): 535 | Fix notifier API URL as per Airbrake docs 536 | 537 | George Ogata (1): 538 | Ignore ActionController::UnknownHttpMethod by default. 539 | 540 | Hrvoje Šimić (59): 541 | move dependencies from Gemfile 542 | CI test only for 3.0.0 for now 543 | use appraisal 544 | use aruba instead of home-grown terminal 545 | fix *ALL* the tests! 546 | remove bundler version 547 | support all major rails versions for now 548 | add bundler dependency 549 | destroy rvmrc 550 | update appraisals 551 | add task for bundling bundler 552 | remove gemfile locks 553 | update appraisals 554 | clean up README 555 | logo is not needed in README 556 | update the integration tests 557 | update testing instructions 558 | use CircleCI for continuous integration 559 | update rake default task 560 | mark heroku tests as wip for now 561 | Clean up the rake task 562 | stop cluttering STDOUT with trace of rake tasks 563 | update supported rails versions 564 | send framework info 565 | use specific version of builder 566 | update appraisals 567 | revert "use specific version of builder" 568 | remove hard dependency on girl_friday 569 | update thoughtbot logo 570 | update test suite to newer Rails versions 571 | unfreezing version 572 | More description about development environments 573 | make sure we don't set env["airbrake.error_id"] for async notices 574 | stop extending Object, use ActiveSupport instead 575 | blank? instead of nil? || empty? 576 | move XSD schema to resources 577 | enable sending to new JSON API (#163) 578 | define headers in Sender 579 | ignore gemfile.locks 580 | make sending to new JSON API disabled by default (#163) 581 | don't use named groups in regexes, they are ruby 1.9 only (#162) 582 | make sure we close the body even if exception occurs (closes #153) 583 | Rails::Application::Configuration.force_ssl is undefined for Rails 3.0.x 584 | update the test suite 585 | update the default rake task 586 | add the ability to pass a single feature to rake test task 587 | tests support Rack::BodyProxy now 588 | use rails 4 compatible routes in tests 589 | remove unnecessary local variables 590 | stop with monkeypatchig of Rails exception middleware 591 | style fixes 592 | require the new middleware in tests 593 | better handler for adding Heroku deploy hooks (#167) 594 | support multiple apps in Heroku deploy hooks task (#166) 595 | read every available parameter for deploy hook from ENV (#168) 596 | fallback to reading API key from ENV for deploy hooks 597 | freshen up Heroku readme 598 | set username and revision from Heroku variables (#168) 599 | automatically get remote origin for deploy hooks (#168) 600 | 601 | Joel Friedlaender (1): 602 | configuring development environments 603 | 604 | Jon Evans (1): 605 | Use "get" instead of "match" for verify route 606 | 607 | Josh Goebel (1): 608 | clean_rack_request_data should also filter out "action_dispatch.secret_token" to prevent passing a Rails applications secret token 609 | 610 | Kyle Wilkinson (1): 611 | Fix broken gemspec with missing file names. MIT-LICENSE is now just called LICENSE and there is no TESTING.md 612 | 613 | Manuel Meurer (1): 614 | Use Airbrake.notify_or_ignore instead of just Airbrake.notify in notify_airbrake controller method 615 | 616 | Marko Šiftar (3): 617 | better Sinatra handling 618 | fix typo 619 | add framework info for Sinatra and Rack 620 | 621 | Morgan Mikel McDaris (3): 622 | fixed the heroku airbrake.rb generation 623 | fixed the heroku airbrake.rb generation 624 | made supported versions into a link 625 | 626 | Pedro Nascimento (1): 627 | Allow virtual attributes to be used in user data instead of just attributes. 628 | 629 | Ryan Souza (1): 630 | Prettier rake exception actions 631 | 632 | cielavenir (1): 633 | airbrake_javascript_notifier_options should be externalized 634 | 635 | 636 | Version 3.1.6 - 2012-10-23 21:15:50 +0200 637 | =============================================================================== 638 | 639 | Hrvoje Šimić (9): 640 | load api key from file and env if not provided for executable 641 | get a list of your projects from command line 642 | create projects from command line 643 | fix cli client host 644 | creating deploys from command line 645 | don't override extension methods 646 | update heroku plan in readme 647 | another fix for heroku readme 648 | don't pollute global namespace with blank? 649 | 650 | Sam Umbach (1): 651 | Send deploy notification on deploy:cold 652 | 653 | 654 | Version 3.1.5 - 2012-10-05 17:32:23 +0200 655 | =============================================================================== 656 | 657 | Hrvoje Šimić (3): 658 | make collected user attributes customizable 659 | enable filtering of env vars for rake handler 660 | add a simple executable 661 | 662 | Morgan Mikel McDaris (1): 663 | rake section added 664 | 665 | Zachary Anker (2): 666 | Add the ability to pass XML directly to send_to_airbrake 667 | Remove active_support require since it's no longer necessary 668 | 669 | 670 | Version 3.1.4 - 2012-09-11 04:31:51 +0200 671 | =============================================================================== 672 | 673 | Ben Arent (1): 674 | Update to MIT license to reflect new ownership. 675 | 676 | Hrvoje Šimić (4): 677 | remove activesupport from runtime dependencies 678 | use different logger for async notices 679 | Merge pull request #118 from exviva/load_initializer_conditionally 680 | symbolize user's keys 681 | 682 | Olek Janiszewski (1): 683 | Fallback to loading whole environment if initializer does not exist 684 | 685 | 686 | Version 3.1.3 - 2012-09-05 18:58:27 +0200 687 | =============================================================================== 688 | 689 | Ben Arent (1): 690 | Removed old mailing list. 691 | 692 | Dylan Smith (1): 693 | Use debug log level for verbose log messages. 694 | 695 | Hrvoje Šimić (21): 696 | add a note for testing against different frameworks 697 | add a scenario to make sure 404s are ignored by default 698 | failing scenario for #100 699 | remove unnecessary bundler/setup requirement 700 | move dependencies from Gemfile to gemspec 701 | send info about the current logged in user 702 | add async notifications 703 | use async? instead of asnyc 704 | add info about logger 705 | prefer provided error message over original exception message 706 | don't load entire environment for deploy task 707 | safely handle render exception 708 | remove unnecessary AirbrakeError 709 | update XML schema 710 | test fixes 711 | clean whitespace 712 | print the failed notice details 713 | update supported rails versions 714 | update scenarios 715 | stop converting notice to xml before passing it to sender 716 | remove logger from rack handler 717 | update supported rails versions 718 | 719 | John Pignata (1): 720 | Cherry-pick Object#blank? extension 721 | 722 | Joshua Wood (2): 723 | rbenv support 724 | Fixes outdated rake feature. 725 | 726 | Matt Colyer (1): 727 | Fix Airbrake so it actually reports data. 728 | 729 | Morgan Mikel McDaris (1): 730 | changed notify to notify_or_ignore 731 | 732 | Sergii Boiko (2): 733 | Refactor config.async to provide custom asynchronous delivery way 734 | Simplify config.async to use only notice param 735 | 736 | grosser (2): 737 | fix exceeded available parameter key space breaks notification, fixes #99 738 | make all tests runnable via ruby test_file.rb by loading the helper absolutely 739 | 740 | 741 | Version 3.1.2 - 2012-06-23 02:27:01 +0200 742 | =============================================================================== 743 | 744 | Hrvoje Šimić (5): 745 | routing errors ignored by default, for #92 746 | use simplecov for test coverage 747 | fix features for javascript 748 | ignore user agents in rack, closes #61 749 | error out if controller is undefined 750 | 751 | 752 | Version 3.1.1 - 2012-06-06 20:35:00 -0700 753 | =============================================================================== 754 | 755 | Hrvoje Šimić (10): 756 | minor fixes for Rakefile 757 | change color of user informer tests 758 | remove unnecessary shim 759 | use shim instead of server response in tests 760 | add a note about informing the user 761 | fix typo in Rakefile 762 | valid mock responses 763 | add a failing scenario for #92 764 | 404s reporting fixed, closes #92 765 | update mocks for rack and sinatra 766 | 767 | Jonathan Siegel (1): 768 | Updated copyright/trademarks 769 | 770 | 771 | Version 3.1.0 - 2012-05-28 02:25:09 +0200 772 | =============================================================================== 773 | 774 | Andre Arko (1): 775 | stop using deprecated RAILS_ROOT 776 | 777 | Benjamin Oakes (5): 778 | notify_airbrake: filter params on Rails 3.1 (and maybe 3.0 also) 779 | `params` is the (eventual) intent, but `hash` is clearer in context 780 | One-liner, per @shime 781 | Exception safety: worst case scenario, report the unfiltered hash 782 | (m) Summarize the cases for future maintainers 783 | 784 | Blake Watters (1): 785 | Modify Rake handler to use Airbrake.notify_or_ignore rather than Airbrake.notify 786 | 787 | Chris Griego (1): 788 | Fix allowing airbrake_env/TO being different from rails_env/RAILS_ENV in deployment notifications. 789 | 790 | David (10): 791 | Merge pull request #33 from cgriego/patch-1 792 | Merge pull request #51 from unnu/master 793 | Merge pull request #56 from GateGuru/rake_handler_fix 794 | Merge pull request #60 from DaPulse/master 795 | Merge pull request #71 from sgonyea/patch-1 796 | Merge pull request #75 from blackhacker/master 797 | Merge pull request #81 from brainopia/patch-1 798 | Merge pull request #82 from ghurrell/fix-readme-stubbing-example 799 | Merge pull request #80 from yanowitz/patch-1 800 | Merge pull request #86 from Playhem/master 801 | 802 | David Palm (5): 803 | Set VERIFY_PEER in rake task 804 | More idiomatic inject 805 | Not quite ready yet. Revert "Heroku references now are to Airbrake." 806 | Adds `pry` to the gems available in test env 807 | Works outside Rails 808 | 809 | Eran Kampf (2): 810 | Fix for apps behind a local proxy (EY App Master) 811 | Changed if statement to one liner 812 | 813 | Erik Ostrom (1): 814 | Updated Heroku README to use Airbrake's new name. 815 | 816 | Gary Rafferty (1): 817 | Fix typo in airbrake.gemspec 818 | 819 | Greg Hurrell (1): 820 | Update stubbing example in README to match method signature 821 | 822 | Hrvoje Šimić (47): 823 | Merge pull request #59 from benjaminoakes/master 824 | Merge pull request #62 from sleparc/master 825 | Merge pull request #63 from benjaminoakes/master 826 | improved readability 827 | added new middleware catcher, fixes #73 828 | Merge pull request #72 from 'jdel/lazyload' 829 | Merge pull request #87 from gary-rafferty/master 830 | Stop using include? to filter parameters 831 | renaming so it's easier to understand 832 | Merge pull request #90 from samoli/patch-1 833 | Merge pull request #68 from cylence/master 834 | read ENV variables from heroku config, fixes #89 835 | check for airbrake_api_key on heroku 836 | Merge pull request #91 from mikz/patch-1 837 | ignore user agents in rails 3.0+ 838 | Merge branch 'master' of github.com:airbrake/airbrake 839 | Merge pull request #79 from morgoth/fix-passing-api-key-as-param-to-rake-task 840 | minor test fix 841 | let's catch errors that happen early in the stack 842 | remove deprecated step definitions 843 | update url in a test 844 | fix required files in gemspec 845 | use top-level namespace 846 | fix requirements 847 | add rvmrc 848 | update server response in scenarios 849 | update heroku mock 850 | remove unnecessary space 851 | prefer the latest stable ruby version 852 | update steps for newer rails versions 853 | support rails 3.2.x with the test suite 854 | update exception catcher 855 | monkeypatch the old rails versions in tests 856 | remove fake exception from env 857 | add sanity to rescue_action_in_public_without_airbrake call 858 | remove note for rails 1.2.x users, we don't support it 859 | support the latest rails versions 860 | add 3.0.11 and 3.0.12 to supported versions 861 | update rack synopsis 862 | log messages for sinatra and rack 863 | make rack and sinatra tests green 864 | update rack example in readme 865 | Update ignored exceptions by default in readme 866 | update explanation how we catch errors in readme 867 | fix formatting 868 | add all supported frameworks to rake test task 869 | make metal tests green 870 | 871 | Jason Yanowitz (2): 872 | remove git dependency from generating gemspec file. causes errors when vendoring this gem in other projects 873 | updated gemspec files specification based on feedback 874 | 875 | Jean-Michel Garnier (1): 876 | Update README.md 877 | 878 | Jonathan Siegel (5): 879 | Heroku references now are to Airbrake. 880 | Merge branch 'master' of github.com:airbrake/airbrake 881 | Added beta support fer cedar. 882 | Added beta support fer cedar. 883 | Migrated to new api.airbrake.io endpoint. 884 | 885 | Jonathan del Strother (1): 886 | Lazily-load actioncontroller 887 | 888 | Leonid Shevtsov (3): 889 | Feature: use a separate API key for Javascript notifications 890 | cleaned up configuration 891 | Merge branch 'master' of git://github.com/airbrake/airbrake 892 | 893 | Michal Cichra (1): 894 | Use id to lookup error instead of error-id. 895 | 896 | Nathan Broadbent (1): 897 | Added Mongoid::Errors::DocumentNotFound to default IGNORED exceptions (same as ActiveRecord::RecordNotFound, for Mongoid.) 898 | 899 | Ravil Bayramgalin (1): 900 | Update lib/airbrake/user_informer.rb 901 | 902 | Ryan L. Cross (1): 903 | Added unix style param for url in the deployhook rake task. 904 | 905 | Sam Oliver (1): 906 | Update hoptoad=>aibrake in rake task example 907 | 908 | Scott Gonyea (1): 909 | Document proxy parameters; namely, that the proxy_host does not require "http://" as a prefix. Ideally, config.proxy= could be given a URI. 910 | 911 | Simon Le Parc (1): 912 | Shouldn't test the native dup method 913 | 914 | Stuart Chaney (1): 915 | Updating README gem instructions for Rails 2.3 with bundler. 916 | 917 | Wojciech Wnętrzak (1): 918 | fixed passing api_key param to Airbrake deploy task 919 | 920 | blackhacker (1): 921 | more detailed error message 922 | 923 | unnu (1): 924 | Fixed TaggedLogging bug in Rails 3 rake test task 925 | 926 | usiegj00 (3): 927 | Merge pull request #46 from eostrom/master 928 | Merge pull request #47 from 21croissants/master 929 | Merge pull request #38 from ndbroadbent/ignore_mongoid_notfound 930 | 931 | 932 | Version 3.0.9 - Thu Dec 15 23:51:38 +0100 2011 933 | =============================================================================== 934 | 935 | David Palm (2): 936 | Merge pull request #45 from spagalloco/patch-1 937 | Pulls in ideas from https://github.com/kidsalsa/airbrake/commit/54982ba83bd6c577a0835b9ba5936c690029244c#L0R2 BUT 938 | - moves #ca_bundle_path to Airbrake::Configuration 939 | - moves #local_cert_path to Airbrake::Configuration 940 | - adds #use_system_ssl_cert_chain? alias to Airbrake::Configuration 941 | - makes Airbrake.configure return the created sender (in addition to yielding) 942 | - stops airbrake deploy tasks duplicate code form the configuration class 943 | - cleanup unused expectations from tests 944 | 945 | Version 3.0.8 - Sun Dec 11 22:14:18 +0100 2011 946 | =============================================================================== 947 | 948 | David Palm (1): 949 | Use OpenSSL::X509::DEFAULT_CERT_FILE to connect only if configured to by setting use_system_ssl_cert_chain to true 950 | 951 | Version 3.0.7 - Sun Dec 11 21:04:08 +0100 2011 952 | =============================================================================== 953 | 954 | David Palm (1): 955 | Adds a :use_system_ssl_cert_chain configuration option to allow use of the system default SSL chain (as opposed to the CAs bundled with Airbrake) - defaults to false 956 | 957 | Version 3.0.6 - Mon Dec 05 16:41:39 +0100 2011 958 | =============================================================================== 959 | 960 | Benjamin Quorning (1): 961 | README updated to reflect name change from Hoptoad to Airbrake 962 | 963 | Darcy Laycock (1): 964 | Explicitly scope calls to Rails.env and such to prevent loading issues when manually requiring parts of airbrake. 965 | 966 | David (1): 967 | Merge pull request #42 from Playhem/fix-issue-34-cherrypicked 968 | 969 | David Czarnecki (6): 970 | Using the Capistrano logger for great justice 971 | Using the Capistrano logger for great justice 972 | Re-organized capistrano task to allow for testing 973 | Fixing conflict 974 | Fixed the name of the capistrano task in the test to be correct. Updated the cucumber feature to look for the right task name. 975 | Change airbrake:notify to airbrake:deploy to be more clear that it is a deploy notification 976 | 977 | David Palm (8): 978 | Removes support for Rails v2.3.12 979 | Documentation glitch 980 | Documenting workaround for issue #39 981 | Using guard&spork for testing 982 | Adding Guardfile 983 | Moves #assert_logged to test helper 984 | Moves http setup code to own method 985 | Not sporking yet 986 | 987 | Florent Guilleux (1): 988 | Change Hoptoad references to Airbrake. 989 | 990 | Gabe Berke-Williams (1): 991 | Merge pull request #10 from Florent2/patch-1 992 | 993 | Harold Giménez (10): 994 | Heroku is still using HOPTOAD_API_KEY, so expect that for now 995 | Bumping to version 3.0 996 | Bumping to version 3.0.1 997 | Fix bug in defining the Airbrake javascript object 998 | Bumping to version 3.0.2 999 | Ensure a valid configuration object is always available on Airbrake.configuration 1000 | Merge remote-tracking branch 'agoragames/master' 1001 | Bumping to version 3.0.3 1002 | Minor fix to Gemfile instructions on README 1003 | Bumping to version 3.0.4 1004 | 1005 | Jonathan Siegel (16): 1006 | Removed class-level caching per jkraemer: Hi, 1007 | Integrated pulls and updated tests. 1008 | Integrated: https://github.com/thoughtbot/hoptoad_notifier/pull/37 1009 | Corrected test. 1010 | Consistent operation. 1011 | Consistent callout during test generation. 1012 | Fixed typo. 1013 | Refreshed supported. 1014 | Resolved: http://help.airbrakeapp.com/discussions/questions/587-airbrake_javascript_notifier-is-escaped-rails-31-haml 1015 | Now running airbrake deploy notifications on the REMOTE machine. 1016 | Added first rev of PEER cert resolution. 1017 | Bumped 3.0.5 1018 | Updated README, fixed JS rescue template missed HT reference. 1019 | Crosslinked docs... 1020 | Fixes for tests. 1021 | Bumping to version 3.0.5 1022 | 1023 | Leonid Shevtsov (3): 1024 | fixed rake handler failing when exception happens before Airbrake has been configured (for example, when running an unknown Rake task) 1025 | fix issue #34 'undefined method to_backtrace for Hash' 1026 | test case for issue #34 1027 | 1028 | Matt Fawcett (1): 1029 | Call #close on the old body after building the new body to prevent thread joining errors 1030 | 1031 | Roman Shterenzon (1): 1032 | Use either Airbrake or Hoptoad object. 1033 | 1034 | Stuart Chaney (1): 1035 | point towards airbrake.io 1036 | 1037 | Thomas Jachmann (1): 1038 | handles exceptions with #to_hash properly 1039 | 1040 | usiegj00 (4): 1041 | Merge pull request #21 from mattfawcett/master 1042 | Merge pull request #12 from leonid-shevtsov/master 1043 | Merge pull request #14 from thomasjachmann/master 1044 | Merge pull request #28 from Sutto/patch-1 1045 | 1046 | 1047 | Version 3.0.5 - 2011-11-08 23:02:07 -0800 1048 | =============================================================================== 1049 | 1050 | Benjamin Quorning (1): 1051 | README updated to reflect name change from Hoptoad to Airbrake 1052 | 1053 | Darcy Laycock (1): 1054 | Explicitly scope calls to Rails.env and such to prevent loading issues when manually requiring parts of airbrake. 1055 | 1056 | David Czarnecki (6): 1057 | Using the Capistrano logger for great justice 1058 | Using the Capistrano logger for great justice 1059 | Re-organized capistrano task to allow for testing 1060 | Fixing conflict 1061 | Fixed the name of the capistrano task in the test to be correct. Updated the cucumber feature to look for the right task name. 1062 | Change airbrake:notify to airbrake:deploy to be more clear that it is a deploy notification 1063 | 1064 | Florent Guilleux (1): 1065 | Change Hoptoad references to Airbrake. 1066 | 1067 | Gabe Berke-Williams (1): 1068 | Merge pull request #10 from Florent2/patch-1 1069 | 1070 | Harold Giménez (10): 1071 | Heroku is still using HOPTOAD_API_KEY, so expect that for now 1072 | Bumping to version 3.0 1073 | Bumping to version 3.0.1 1074 | Fix bug in defining the Airbrake javascript object 1075 | Bumping to version 3.0.2 1076 | Ensure a valid configuration object is always available on Airbrake.configuration 1077 | Merge remote-tracking branch 'agoragames/master' 1078 | Bumping to version 3.0.3 1079 | Minor fix to Gemfile instructions on README 1080 | Bumping to version 3.0.4 1081 | 1082 | Jonathan Siegel (15): 1083 | Removed class-level caching per jkraemer: Hi, 1084 | Integrated pulls and updated tests. 1085 | Integrated: https://github.com/thoughtbot/hoptoad_notifier/pull/37 1086 | Corrected test. 1087 | Consistent operation. 1088 | Consistent callout during test generation. 1089 | Fixed typo. 1090 | Refreshed supported. 1091 | Resolved: http://help.airbrakeapp.com/discussions/questions/587-airbrake_javascript_notifier-is-escaped-rails-31-haml 1092 | Now running airbrake deploy notifications on the REMOTE machine. 1093 | Added first rev of PEER cert resolution. 1094 | Bumped 3.0.5 1095 | Updated README, fixed JS rescue template missed HT reference. 1096 | Crosslinked docs... 1097 | Fixes for tests. 1098 | 1099 | Leonid Shevtsov (1): 1100 | fixed rake handler failing when exception happens before Airbrake has been configured (for example, when running an unknown Rake task) 1101 | 1102 | Matt Fawcett (1): 1103 | Call #close on the old body after building the new body to prevent thread joining errors 1104 | 1105 | Roman Shterenzon (1): 1106 | Use either Airbrake or Hoptoad object. 1107 | 1108 | Stuart Chaney (1): 1109 | point towards airbrake.io 1110 | 1111 | Thomas Jachmann (1): 1112 | handles exceptions with #to_hash properly 1113 | 1114 | usiegj00 (4): 1115 | Merge pull request #21 from mattfawcett/master 1116 | Merge pull request #12 from leonid-shevtsov/master 1117 | Merge pull request #14 from thomasjachmann/master 1118 | Merge pull request #28 from Sutto/patch-1 1119 | 1120 | 1121 | 1122 | Version 3.0.4 - Mon Sep 12 08:25:04 -0400 2011 1123 | =============================================================================== 1124 | David Czarnecki(1): 1125 | Change deploy task back to airbrake:deploy 1126 | Harold Gimenez(1): 1127 | README updates 1128 | 1129 | Version 3.0.3 - Sat Sep 03 13:18:26 -0400 2011 1130 | =============================================================================== 1131 | David Czarnecki(1): 1132 | Use capistrano's logger, improve tests around capistrano deploy. 1133 | Florent Guilleux(1): 1134 | README updates 1135 | 1136 | Version 3.0.2 - Mon Aug 29 10:32:04 -0400 2011 1137 | =============================================================================== 1138 | Harold Gimenez(1) 1139 | Fix bug on the Hoptoad to Airbrake fallback code on the javascript notifier. 1140 | 1141 | Version 3.0.1 - Mon Aug 29 08:37:24 -0400 2011 1142 | =============================================================================== 1143 | Roman Shterenzon(1): 1144 | Use either Airbrake or Hoptoad object on javascript notifier 1145 | 1146 | Version 3.0 - Fri Aug 26 08:55:47 -0400 2011 1147 | =============================================================================== 1148 | Harold Gimenez: 1149 | Continue to use HOPTOAD_API_KEY for heroku users' API key env variable 1150 | 1151 | Version 3.0.rc2 - Wed Aug 24 15:03:46 -0400 2011 1152 | =============================================================================== 1153 | 1154 | Harold Gimenez: 1155 | Revert broken commit around exceptions that respond to #to_hash 1156 | Support latest versions of Rails. 1157 | 1158 | 1159 | Version 3.0.rc1 - Fri Aug 19 08:51:53 -0400 2011 1160 | =============================================================================== 1161 | 1162 | Jonathan Yurek and Harold Gimenez 1163 | Rename to Airbrake 1164 | 1165 | Version 2.4.9 - Wed Mar 30 09:04:53 -0400 2011 1166 | =============================================================================== 1167 | 1168 | Jonathan Yurek(1): 1169 | The User Informer should adhere to only the Rack spec. 1170 | 1171 | Version 2.4.8 - Mon Mar 21 11:11:16 -0400 2011 1172 | =============================================================================== 1173 | 1174 | Jonathan Yurek(1): 1175 | Prevent infinite loops from recursive data structures. 1176 | 1177 | Version 2.4.7 - Thu Mar 10 16:21:31 -0500 2011 1178 | =============================================================================== 1179 | 1180 | Jonathan Yurek(1): 1181 | Rails generator requires './config/boot' for 1.9.2 compatibility. 1182 | 1183 | Version 2.4.6 - Tue Feb 15 15:51:17 -0500 2011 1184 | =============================================================================== 1185 | 1186 | Jonathan Yurek(1): 1187 | Modify the error page's body in-place. 1188 | 1189 | Version 2.4.5 - Wed Feb 02 13:24:29 -0500 2011 1190 | =============================================================================== 1191 | 1192 | Jonathan Yurek (1): 1193 | Don't require Rack::Lock's presence in the middleware for UserInformer 1194 | 1195 | 1196 | Version 2.4.4 - Fri Jan 28 13:50:10 -0500 2011 1197 | =============================================================================== 1198 | 1199 | Matt Jankowski (1): 1200 | Change the javascript notifier from a config option to a helper method 1201 | 1202 | Jonathan Yurek (1): 1203 | Show the javascript notifier prevents XSS attempts from request.url 1204 | 1205 | Version 2.4.3 - Wed Jan 26 11:35:15 -0500 2011 1206 | =============================================================================== 1207 | 1208 | Jon Yurek (1): 1209 | Allow the application to present the Hoptoad error number to the user 1210 | 1211 | 1212 | Version 2.4.2 - Sun Jan 09 09:37:31 -0500 2011 1213 | =============================================================================== 1214 | 1215 | Matt Jankowski (1): 1216 | fix issue where the gsub to replace the html head with javascript was removing the head element entirely 1217 | 1218 | 1219 | Version 2.4.1 - Sat Jan 08 12:17:15 -0500 2011 1220 | =============================================================================== 1221 | 1222 | Matt Jankowski (1): 1223 | restore method which may have been accidentally removed? 1224 | 1225 | 1226 | Version 2.4.0 - Thu Jan 06 15:03:58 -0500 2011 1227 | =============================================================================== 1228 | 1229 | Jason Morrison (1): 1230 | Remove official support for very old Rails version going forward 1231 | 1232 | Version 2.3.14 - Wed Jan 05 14:06:12 -0500 2011 1233 | =============================================================================== 1234 | 1235 | Jason Morrison (1): 1236 | Fix 'require' path 1237 | 1238 | Version 2.3.13 - Mon Jan 03 15:56:20 -0500 2011 1239 | =============================================================================== 1240 | 1241 | Dan Croak (1): 1242 | including twiddle wakka in install instructions 1243 | 1244 | Emma Lindsay (5): 1245 | Sends more javascript information back to hoptaod 1246 | Merge branch 'js_notifier_default_fields' 1247 | Bumping to version 2.3.10 1248 | Updated jferris-mocha to bourne 1249 | Update readme to show quotes around error names in ignores 1250 | 1251 | Jason Morrison (8): 1252 | wip: Supply default url, component, action for JS notifier 1253 | gracefully fall back to require 'activesupport' if require 'active_support' fails 1254 | Add non-capistrano deploy instructions 1255 | Add instructions for heroku gem to Heroku addon README 1256 | Add AbstractController::ActionNotFound to default ignore list 1257 | Bumping to version 2.3.12 1258 | Bugfix: JS Notifier will now insert itself even when tag has attributes 1259 | Add Heroku deploy notification 1260 | 1261 | Jon Yurek (11): 1262 | Require bourne, run right cucumber task 1263 | Get the API key from Heroku 1264 | Bumped version: 2.3.11 1265 | Getting green cucumber stories 1266 | Fakes out the heroku command for cucumber. 1267 | Mount the metal endpoint in Rails 3 tests. 1268 | Metal test mounts at /metal 1269 | Supported versions: 2.3.9, 2.3.10, and 3.0.1 1270 | Return non-zero on cucumber failure. 1271 | Controller info for older Rails-es is different. 1272 | Remove Rails 2.0.2 from official support. Added 3.0.2+3 1273 | 1274 | Trevor Turk (1): 1275 | Fix default ignores in the README 1276 | 1277 | 1278 | Version 2.3.12 - Wed Nov 03 13:53:18 -0400 2010 1279 | =============================================================================== 1280 | 1281 | In general: Update gems, improve testing, improve documentation, improve 1282 | javascript notifier. 1283 | 1284 | Emma Lindsay (4): 1285 | Sends more javascript information back to hoptaod 1286 | Merge branch 'js_notifier_default_fields' 1287 | Bumping to version 2.3.10 1288 | Updated jferris-mocha to bourne 1289 | 1290 | Jason Morrison (5): 1291 | wip: Supply default url, component, action for JS notifier 1292 | gracefully fall back to require 'activesupport' if require 'active_support' fails 1293 | Add non-capistrano deploy instructions 1294 | Add instructions for heroku gem to Heroku addon README 1295 | Add AbstractController::ActionNotFound to default ignore list 1296 | 1297 | Jon Yurek (9): 1298 | Require bourne, run right cucumber task 1299 | Get the API key from Heroku 1300 | Bumped version: 2.3.11 1301 | Getting green cucumber stories 1302 | Fakes out the heroku command for cucumber. 1303 | Mount the metal endpoint in Rails 3 tests. 1304 | Metal test mounts at /metal 1305 | Supported versions: 2.3.9, 2.3.10, and 3.0.1 1306 | Return non-zero on cucumber failure. 1307 | 1308 | 1309 | Version 2.3.10 - Mon Oct 18 17:07:56 -0400 2010 1310 | =============================================================================== 1311 | 1312 | Emma Lindsay (2): 1313 | Sends more javascript information back to hoptaod 1314 | Merge branch 'js_notifier_default_fields' 1315 | 1316 | Jason Morrison (2): 1317 | wip: Supply default url, component, action for JS notifier 1318 | gracefully fall back to require 'activesupport' if require 'active_support' fails 1319 | 1320 | 1321 | Version 2.3.9 - 2010-10-18 1322 | =============================================================================== 1323 | 1324 | This patch release contains a handful of bugfixes, and ensures: 1325 | If hoptoadapp.com is completely unreachable by HTTP, your app is not affected. 1326 | Controller method #notify_hoptoad is available in Rails 3. Thanks contributor Kyle Crum! 1327 | 1328 | Chad Pytel (1): 1329 | also handle Errno::ECONNREFUSED and other http errors 1330 | 1331 | Jason Morrison (4): 1332 | Add gem versions to test suite 1333 | Revert "Revert "attempt to debug mail sending on staging"" 1334 | Adding Heroku notifier readme 1335 | gracefully fall back to require 'activesupport' if require 'active_support' fails 1336 | 1337 | Jon Yurek (2): 1338 | Bumping version to 2.3.8 1339 | Adds builder to the gemspec 1340 | 1341 | Kyle Crum (3): 1342 | notify_hoptoad now works in rails 3 controllers 1343 | more sane way of testing for rails 3 controller methods 1344 | added a scenario for using the notify_hoptoad method within a controller 1345 | 1346 | 1347 | Version 2.3.7 - 2010-09-15 1348 | =============================================================================== 1349 | 1350 | Jason Morrison (5): 1351 | Add ./ prefix to require for 1.9.2 1352 | More helpful message for testing without ENV['RAILS_VERSION'] 1353 | Support Rails 3.0.0, not 3.0.0.rc 1354 | This wasn't actually a fix (it regressed tests): Revert "Fix modifying params_filters" 1355 | Correct the #also_use_rack_params_filters method 1356 | 1357 | Joshua Clayton (1): 1358 | Fix modifying params_filters 1359 | 1360 | Nick Quaranto (2): 1361 | s/RSpec/Spec for matchers 1362 | use Sinatra::Default instead of Sinatra::Base 1363 | 1364 | 1365 | Version 2.3.6 - 2010-08-30 1366 | =============================================================================== 1367 | 1368 | Daniel Barron (1): 1369 | Initializer configuration overrides Railtie configuration if set 1370 | 1371 | Joshua Clayton (1): 1372 | Remove rack.request.form_vars 1373 | 1374 | Tristan Dunn (1): 1375 | Move Rails JS scenarios into separate feature and correctly support HTTPS when secure is enabled on the notifier. 1376 | 1377 | 1378 | Version 2.3.5 - 2010-08-13 1379 | =============================================================================== 1380 | 1381 | Alexey Palazhchenko (1): 1382 | Actually call #to_hash. 1383 | 1384 | Joshua Clayton (1): 1385 | Trace hoptoad:test task when running generator for anything before Rails3 1386 | 1387 | 1388 | Version 2.3.4 - 2010-08-10 1389 | =============================================================================== 1390 | 1391 | Tristan Dunn (1): 1392 | Only include the JS notifier in public environments. 1393 | 1394 | 1395 | Version 2.3.3 - 2010-08-04 1396 | =============================================================================== 1397 | 1398 | Tristan Dunn (1): 1399 | Initial injection of JS notifier. 1400 | 1401 | 1402 | Version 2.3.2 - 2010-07-06 1403 | =============================================================================== 1404 | 1405 | Josh Clayton(1): 1406 | Handle instances when Rack's action_dispach.parameter_filter is nil 1407 | 1408 | 1409 | Version 2.3.1 - 2010-07-02 1410 | =============================================================================== 1411 | 1412 | Jason Morrison (2): 1413 | Use the Rails 3 params filters when available 1414 | Filter session hash using Hoptoad config.params_filters, in addition to params 1415 | 1416 | 1417 | Version 2.3.0 - 2010-06-24 1418 | =============================================================================== 1419 | 1420 | Jason Morrison (5): 1421 | Add integration test for rails 3.0.0.beta4 1422 | Added feature: Support the Heroku addon in the generator 1423 | Add --heroku flag to generator to support ENV['HOPTOAD_API_KEY'] 1424 | Reflect a copy change in rails.feature for --heroku generator flag 1425 | Support the proxy configuration options when notifying Hoptoad of a deploy (hat tip @gudleik) 1426 | 1427 | 1428 | Version 2.2.6 - 2010-06-02 1429 | =============================================================================== 1430 | 1431 | Jason Morrison (1): 1432 | For Rails 3, just use the Rack middleware instead of specifying a location to insert_after 1433 | 1434 | 1435 | Version 2.2.5 - 2010-06-02 1436 | =============================================================================== 1437 | 1438 | Jason Morrison (1): 1439 | Add documentation for Rails 3.x installation 1440 | 1441 | 1442 | Version 2.2.4 - 2010-06-02 1443 | =============================================================================== 1444 | 1445 | Jason Morrison (1): 1446 | Add a note to README about removing the explicit Catcher #include in ApplicationController 1447 | 1448 | 1449 | Version 2.2.3 - 2010-06-02 1450 | =============================================================================== 1451 | 1452 | Summary: Fixed a variety of issues for Rails 3.0.0.beta3, 1453 | Fixed a bug when using Vlad to deploy instead of Capistrano 1454 | Give better error output when gem is not installed 1455 | 1456 | Chad Pytel (2): 1457 | revise gem unpack instructions step 1458 | Merge branch 'master' of github.com:thoughtbot/hoptoad_notifier 1459 | 1460 | Dan Lawless (1): 1461 | don't append capistrano details to config.deploy.rb when target app uses Vlad 1462 | 1463 | Jason Morrison (7): 1464 | LH-556 Clarify sending ENV environment variables 1465 | Starting to add features for Rails 3 1466 | Make rails rake tasks depend on gem-making tasks 1467 | Start to get Rails 3 features to pass 1468 | require fileutils to reflect rubygems 1.3.6 change 1469 | Support ENV['CUCUMBER_FORMAT'] in rails cucumber tasks for testing 1470 | Fix the initializer syntax in the Rails 3 Railtie 1471 | 1472 | Joe Ferris (11): 1473 | Got the generator running and a request dispatched to the test endpoint 1474 | Fixed logging in hoptoad:test rake task 1475 | Separated Rails 2 and 3 entry 1476 | Support bundler 1477 | Rails 3 generator works with an existing api key 1478 | Extract request info from rack env 1479 | Detect presence of the plugin 1480 | Added a capistrano hook for Rails 3 1481 | Fixed rack/sinatra being broken without active_support 1482 | Fixes for earlier versions of Rails 1483 | Fixed Rails 3 generator not to append cap hooks for vlad deploys 1484 | 1485 | Josh Kalderimis (7): 1486 | updated railtie to work with the new rails 3 middleware api 1487 | railtie_name is deprecated 1488 | updated app_middleware call to use string version as to make sure constant is loaded 1489 | moved generator using the new rails 3 convention 1490 | update path to template for Rails 3 generator 1491 | correction to referencing of the rails application in rails3_tasks 1492 | add environment_name and project_root back to rails 3 railtie 1493 | 1494 | Joshua Nichols (1): 1495 | Handle gem not being installed more gracefully. 1496 | 1497 | 1498 | Version 2.2.2 - 2010-03-10 1499 | =============================================================================== 1500 | 1501 | Chad Pytel (1): 1502 | document proxy support 1503 | 1504 | Joe Ferris (8): 1505 | Added upgrade instructions to the README 1506 | Give a clearer error message when generating a Rails app fails 1507 | Fail loudly when a gem can't be vendored 1508 | Debugging rubygems issues 1509 | Explicitly specify the gem paths 1510 | Less noisy 1511 | Restore gem path after vendoring 1512 | Fixed a typo 1513 | 1514 | Jon Yurek (1): 1515 | Added notice about removing hoptoad rake tasks to upgrade gem 1516 | 1517 | Mike Burns (1): 1518 | Remove stray file with notes in it 1519 | 1520 | 1521 | Version 2.2.1 - 2010-03-10 1522 | =============================================================================== 1523 | 1524 | Jason Morrison (3): 1525 | LH-629 Ensure notifier is not considered a framework gem 1526 | Removing things-the-generator-must-do file 1527 | Add rake cucumber:wip:rails* tasks for work-in-progress features 1528 | 1529 | 1530 | Version 2.2.0 - 2010-02-18 1531 | =============================================================================== 1532 | 1533 | Bumping the version from 2.1.4 to 2.2.0 since adding Rack support warrants a minor version. 1534 | 1535 | Jason Morrison (1): 1536 | Stringify array elements when making assertions about Notice XML for 1.9 compatibility 1537 | 1538 | 1539 | Version 2.1.4 - 2010-02-12 1540 | =============================================================================== 1541 | 1542 | Chad Pytel (2): 1543 | add more info to README for 1.2.6 1544 | fix gem unpack line for 1.2.6 1545 | 1546 | Jason Morrison (2): 1547 | Adding additional instructions for Rails 1.2.6 1548 | Typesetting in README.rdoc 1549 | 1550 | Joe Ferris (11): 1551 | Separating Rails functionality out more 1552 | Initial Rack middleware 1553 | Extract request info from rack env 1554 | Added integration tests for rescuing 1555 | Fixed reporting of Rails version 1556 | Small refactoring 1557 | Automatically add Rack middleware for Rails apps that support it (catches exceptions from Metal) 1558 | Added an integration test and docs for rack apps 1559 | Added integration/readme coverage of Sinatra apps 1560 | Added docs to HoptoadNotifier::Rack 1561 | Require rack in tests for older versions of Rails; use active_support instead of activesupport 1562 | 1563 | Nick Quaranto (3): 1564 | Fixing the capistrano hook bit in the readme 1565 | Adding changeling:minor and changeling:patch to automate notifier releases 1566 | Adding rake changeling:push 1567 | --------------------------------------------------------------------------------