airbrakeV4rails5 4.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1716 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +6 -0
  5. data/INSTALL +20 -0
  6. data/LICENSE +61 -0
  7. data/README.md +148 -0
  8. data/README_FOR_HEROKU_ADDON.md +102 -0
  9. data/Rakefile +179 -0
  10. data/TESTED_AGAINST +7 -0
  11. data/airbrake.gemspec +41 -0
  12. data/bin/airbrake +12 -0
  13. data/features/metal.feature +34 -0
  14. data/features/rack.feature +60 -0
  15. data/features/rails.feature +324 -0
  16. data/features/rake.feature +33 -0
  17. data/features/sinatra.feature +126 -0
  18. data/features/step_definitions/file_steps.rb +14 -0
  19. data/features/step_definitions/rack_steps.rb +27 -0
  20. data/features/step_definitions/rails_application_steps.rb +267 -0
  21. data/features/step_definitions/rake_steps.rb +22 -0
  22. data/features/support/airbrake_shim.rb.template +11 -0
  23. data/features/support/aruba.rb +5 -0
  24. data/features/support/env.rb +39 -0
  25. data/features/support/matchers.rb +35 -0
  26. data/features/support/rails.rb +156 -0
  27. data/features/support/rake/Rakefile +77 -0
  28. data/features/user_informer.feature +57 -0
  29. data/generators/airbrake/airbrake_generator.rb +94 -0
  30. data/generators/airbrake/lib/insert_commands.rb +34 -0
  31. data/generators/airbrake/lib/rake_commands.rb +24 -0
  32. data/generators/airbrake/templates/airbrake_tasks.rake +25 -0
  33. data/generators/airbrake/templates/capistrano_hook.rb +6 -0
  34. data/generators/airbrake/templates/initializer.rb +4 -0
  35. data/install.rb +1 -0
  36. data/lib/airbrake.rb +191 -0
  37. data/lib/airbrake/backtrace.rb +103 -0
  38. data/lib/airbrake/capistrano.rb +103 -0
  39. data/lib/airbrake/capistrano3.rb +3 -0
  40. data/lib/airbrake/cli/client.rb +76 -0
  41. data/lib/airbrake/cli/options.rb +45 -0
  42. data/lib/airbrake/cli/printer.rb +33 -0
  43. data/lib/airbrake/cli/project.rb +17 -0
  44. data/lib/airbrake/cli/project_factory.rb +33 -0
  45. data/lib/airbrake/cli/runner.rb +49 -0
  46. data/lib/airbrake/cli/validator.rb +8 -0
  47. data/lib/airbrake/configuration.rb +366 -0
  48. data/lib/airbrake/jobs/send_job.rb +7 -0
  49. data/lib/airbrake/notice.rb +411 -0
  50. data/lib/airbrake/rack.rb +64 -0
  51. data/lib/airbrake/rails.rb +45 -0
  52. data/lib/airbrake/rails/action_controller_catcher.rb +32 -0
  53. data/lib/airbrake/rails/controller_methods.rb +146 -0
  54. data/lib/airbrake/rails/error_lookup.rb +35 -0
  55. data/lib/airbrake/rails/middleware.rb +63 -0
  56. data/lib/airbrake/rails3_tasks.rb +126 -0
  57. data/lib/airbrake/railtie.rb +44 -0
  58. data/lib/airbrake/rake_handler.rb +75 -0
  59. data/lib/airbrake/response.rb +29 -0
  60. data/lib/airbrake/sender.rb +213 -0
  61. data/lib/airbrake/shared_tasks.rb +59 -0
  62. data/lib/airbrake/sidekiq.rb +8 -0
  63. data/lib/airbrake/sinatra.rb +40 -0
  64. data/lib/airbrake/tasks.rb +81 -0
  65. data/lib/airbrake/tasks/airbrake.cap +28 -0
  66. data/lib/airbrake/user_informer.rb +36 -0
  67. data/lib/airbrake/utils/params_cleaner.rb +141 -0
  68. data/lib/airbrake/utils/rack_filters.rb +45 -0
  69. data/lib/airbrake/version.rb +3 -0
  70. data/lib/airbrake_tasks.rb +62 -0
  71. data/lib/rails/generators/airbrake/airbrake_generator.rb +155 -0
  72. data/lib/templates/rescue.erb +91 -0
  73. data/rails/init.rb +1 -0
  74. data/resources/README.md +34 -0
  75. data/resources/airbrake_2_4.xsd +89 -0
  76. data/resources/airbrake_3_0.json +52 -0
  77. data/resources/ca-bundle.crt +3376 -0
  78. data/script/integration_test.rb +35 -0
  79. data/test/airbrake_tasks_test.rb +161 -0
  80. data/test/backtrace_test.rb +215 -0
  81. data/test/capistrano_test.rb +44 -0
  82. data/test/configuration_test.rb +303 -0
  83. data/test/controller_methods_test.rb +230 -0
  84. data/test/helper.rb +233 -0
  85. data/test/integration.rb +13 -0
  86. data/test/integration/catcher_test.rb +371 -0
  87. data/test/logger_test.rb +79 -0
  88. data/test/notice_test.rb +494 -0
  89. data/test/notifier_test.rb +288 -0
  90. data/test/params_cleaner_test.rb +204 -0
  91. data/test/rack_test.rb +62 -0
  92. data/test/rails_initializer_test.rb +36 -0
  93. data/test/recursion_test.rb +10 -0
  94. data/test/response_test.rb +18 -0
  95. data/test/sender_test.rb +335 -0
  96. data/test/support/response_shim.xml +4 -0
  97. data/test/user_informer_test.rb +29 -0
  98. metadata +469 -0
@@ -0,0 +1,45 @@
1
+ require 'airbrake'
2
+ require 'airbrake/rails/controller_methods'
3
+ require 'airbrake/rails/action_controller_catcher'
4
+ require 'airbrake/rails/error_lookup'
5
+
6
+ module Airbrake
7
+ module Rails
8
+ def self.initialize
9
+ if defined?(ActionController::Base)
10
+ ActionController::Base.send(:include, Airbrake::Rails::ActionControllerCatcher)
11
+ ActionController::Base.send(:include, Airbrake::Rails::ErrorLookup)
12
+ ActionController::Base.send(:include, Airbrake::Rails::ControllerMethods)
13
+ end
14
+
15
+ rails_logger = if defined?(::Rails.logger)
16
+ ::Rails.logger
17
+ elsif defined?(RAILS_DEFAULT_LOGGER)
18
+ RAILS_DEFAULT_LOGGER
19
+ end
20
+
21
+ if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
22
+ if defined?(::ActionController::Failsafe)
23
+ ::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
24
+ Airbrake::Rack
25
+ end
26
+ if defined?(::Rack::Lock)
27
+ ::Rails.configuration.middleware.insert_after 'Rack::Lock',
28
+ Airbrake::UserInformer
29
+ else
30
+ ::Rails.configuration.middleware.insert_before 'Rack::Runtime',
31
+ Airbrake::UserInformer
32
+ end
33
+ end
34
+
35
+ Airbrake.configure(true) do |config|
36
+ config.logger = rails_logger
37
+ config.environment_name = defined?(::Rails.env) && ::Rails.env || defined?(RAILS_ENV) && RAILS_ENV
38
+ config.project_root = defined?(::Rails.root) && ::Rails.root || defined?(RAILS_ROOT) && RAILS_ROOT
39
+ config.framework = defined?(::Rails.version) && "Rails: #{::Rails.version}" || defined?(::Rails::VERSION::STRING) && "Rails: #{::Rails::VERSION::STRING}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ Airbrake::Rails.initialize
@@ -0,0 +1,32 @@
1
+ module Airbrake
2
+ module Rails
3
+ module ActionControllerCatcher
4
+
5
+ # Sets up an alias chain to catch exceptions for Rails 2
6
+ def self.included(base) #:nodoc:
7
+ if base.method_defined?(:rescue_action_in_public)
8
+ base.send(:alias_method, :rescue_action_in_public_without_airbrake, :rescue_action_in_public)
9
+ base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_airbrake)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ # Overrides the rescue_action method in ActionController::Base, but does not inhibit
16
+ # any custom processing that is defined with Rails 2's exception helpers.
17
+ def rescue_action_in_public_with_airbrake(exception)
18
+ unless airbrake_ignore_user_agent?
19
+ error_id = Airbrake.notify_or_ignore(exception, airbrake_request_data)
20
+ request.env['airbrake.error_id'] = error_id
21
+ end
22
+ rescue_action_in_public_without_airbrake(exception)
23
+ end
24
+
25
+ def airbrake_ignore_user_agent? #:nodoc:
26
+ # Rails 1.2.6 doesn't have request.user_agent, so check for it here
27
+ user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
28
+ Airbrake.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,146 @@
1
+ module Airbrake
2
+ module Rails
3
+ module ControllerMethods
4
+
5
+ SLASH = "/"
6
+
7
+ def airbrake_request_data
8
+ {
9
+ :parameters => airbrake_filter_if_filtering(to_hash(params)),
10
+ :session_data => airbrake_filter_if_filtering(airbrake_session_data),
11
+ :controller => params[:controller],
12
+ :action => params[:action],
13
+ :url => airbrake_request_url,
14
+ :cgi_data => airbrake_filter_if_filtering(request.env),
15
+ :user => airbrake_current_user
16
+ }
17
+ end
18
+
19
+ private
20
+
21
+ def to_hash(params)
22
+ # Rails <= 4
23
+ return params.to_hash if params.respond_to?(:to_hash)
24
+
25
+ # Rails >= 5
26
+ params.to_unsafe_h
27
+ end
28
+
29
+ # This method should be used for sending manual notifications while you are still
30
+ # inside the controller. Otherwise it works like Airbrake.notify.
31
+ def notify_airbrake(hash_or_exception)
32
+ unless airbrake_local_request?
33
+ Airbrake.notify_or_ignore(hash_or_exception, airbrake_request_data)
34
+ end
35
+ end
36
+
37
+ def airbrake_local_request?
38
+ if defined?(::Rails.application.config)
39
+ ::Rails.application.config.consider_all_requests_local || (request.local? && (!request.env["HTTP_X_FORWARDED_FOR"]))
40
+ else
41
+ consider_all_requests_local || (local_request? && (!request.env["HTTP_X_FORWARDED_FOR"]))
42
+ end
43
+ end
44
+
45
+ def airbrake_ignore_user_agent? #:nodoc:
46
+ # Rails 1.2.6 doesn't have request.user_agent, so check for it here
47
+ user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
48
+ Airbrake.configuration.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
49
+ end
50
+
51
+
52
+ def airbrake_filter_if_filtering(hash)
53
+ return hash if ! hash.is_a?(Hash)
54
+
55
+ if respond_to?(:filter_parameters) # Rails 2
56
+ filter_parameters(hash)
57
+ elsif rails_3_or_4?
58
+ filter_rails3_parameters(hash)
59
+ else
60
+ hash
61
+ end
62
+ end
63
+
64
+ def rails_3_or_4?
65
+ defined?(::Rails.version) && ::Rails.version =~ /\A[34]/
66
+ end
67
+
68
+ def filter_rails3_parameters(hash)
69
+ ActionDispatch::Http::ParameterFilter.new(
70
+ ::Rails.application.config.filter_parameters
71
+ ).filter(recursive_stringify_keys(hash))
72
+ end
73
+
74
+ def recursive_stringify_keys(hash)
75
+ hash = hash.stringify_keys
76
+ hash.each do |k, v|
77
+ if v.is_a?(Hash)
78
+ hash[k] = v.respond_to?(:stringify_keys) ? recursive_stringify_keys(v) : nil # Rack::Session::Abstract::SessionHash has a stringify_keys method we should not call
79
+ end
80
+ end
81
+ hash
82
+ end
83
+
84
+ def airbrake_session_data
85
+ if session
86
+ if session.respond_to?(:to_hash)
87
+ session.to_hash
88
+ else
89
+ session.data
90
+ end
91
+ else
92
+ {:session => 'no session found'}
93
+ end
94
+ end
95
+
96
+ def airbrake_request_url
97
+ url = "#{request.protocol}#{request.host}"
98
+
99
+ unless [80, 443].include?(request.port)
100
+ url << ":#{request.port}"
101
+ end
102
+
103
+ unless request.fullpath[0] == SLASH
104
+ url << SLASH
105
+ end
106
+
107
+ url << request.fullpath
108
+ end
109
+
110
+ def airbrake_current_user
111
+ user = fetch_user
112
+
113
+ if user
114
+ Airbrake.configuration.user_attributes.map(&:to_sym).inject({}) do |hsh, attr|
115
+ begin
116
+ hsh[attr] = user.send(attr) if user.respond_to? attr
117
+ hsh
118
+ rescue
119
+ hsh
120
+ end
121
+ end
122
+ else
123
+ {}
124
+ end
125
+ end
126
+
127
+ def fetch_user
128
+ if defined?(current_user)
129
+ current_user
130
+ elsif defined?(current_member)
131
+ current_member
132
+ else
133
+ nil
134
+ end
135
+ rescue
136
+ nil
137
+ ensure
138
+ # The Airbrake middleware is first in the chain, before ActiveRecord::ConnectionAdapters::ConnectionManagement
139
+ # kicks in to do its thing. This can cause the connection pool to run out of connections.
140
+ if defined?(ActiveRecord::Base) && ActiveRecord::Base.respond_to?(:clear_active_connections!)
141
+ ActiveRecord::Base.clear_active_connections!
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,35 @@
1
+ module Airbrake
2
+ module Rails
3
+ module ErrorLookup
4
+
5
+ # Sets up an alias chain to catch exceptions when Rails does
6
+ def self.included(base) #:nodoc:
7
+ if base.method_defined?(:rescue_action_locally)
8
+ base.send(:alias_method, :rescue_action_locally_without_airbrake, :rescue_action_locally)
9
+ base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_airbrake)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def rescue_action_locally_with_airbrake(exception)
16
+ result = rescue_action_locally_without_airbrake(exception)
17
+
18
+ if Airbrake.configuration.development_lookup
19
+ path = File.join(File.dirname(__FILE__), '..', '..', 'templates', 'rescue.erb')
20
+ notice = Airbrake.build_lookup_hash_for(exception, airbrake_request_data)
21
+
22
+ result << @template.render(
23
+ :file => path,
24
+ :use_full_path => false,
25
+ :locals => { :host => Airbrake.configuration.host,
26
+ :api_key => Airbrake.configuration.api_key,
27
+ :notice => notice })
28
+ end
29
+
30
+ result
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,63 @@
1
+ module Airbrake
2
+ module Rails
3
+ # Rack middleware for Rails applications. Any errors raised by the upstream
4
+ # application will be delivered to Airbrake and re-raised.
5
+ #
6
+ class Middleware
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ begin
13
+ response = @app.call(env)
14
+ rescue Exception => exception
15
+ env['airbrake.error_id'] = notify_airbrake(env, exception)
16
+ raise exception
17
+ end
18
+
19
+ if framework_exception = env["action_dispatch.exception"]
20
+ env["airbrake.error_id"] = notify_airbrake(env, framework_exception)
21
+ end
22
+
23
+ response
24
+ end
25
+
26
+ private
27
+
28
+ def controller(env)
29
+ env["action_controller.instance"]
30
+ end
31
+
32
+ def after_airbrake_handler(env, exception)
33
+ if controller(env).respond_to?(:rescue_action_in_public_without_airbrake)
34
+ controller(env).rescue_action_in_public_without_airbrake(exception)
35
+ end
36
+ end
37
+
38
+ def notify_airbrake(env, exception)
39
+ unless ignored_user_agent? env
40
+ error_id = Airbrake.notify_or_ignore(exception, request_data(env))
41
+ after_airbrake_handler(env, exception)
42
+ error_id
43
+ end
44
+ end
45
+
46
+ def request_data(env)
47
+ if controller(env).respond_to?(:airbrake_request_data)
48
+ controller(env).airbrake_request_data
49
+ else
50
+ {:rack_env => env}
51
+ end
52
+ end
53
+
54
+ def ignored_user_agent?(env)
55
+ true if Airbrake.
56
+ configuration.
57
+ ignore_user_agent.
58
+ flatten.
59
+ any? { |ua| ua === env['HTTP_USER_AGENT'] }
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,126 @@
1
+ require 'airbrake'
2
+ require File.join(File.dirname(__FILE__), 'shared_tasks')
3
+
4
+ def stub_rake_exception_handling!
5
+ # Override error handling in Rake so we don't clutter STDERR
6
+ # with unnecesarry stack trace
7
+ Rake.application.instance_eval do
8
+ class << self
9
+ def display_error_message_silent(exception)
10
+ puts exception
11
+ end
12
+ alias_method :display_error_message_old, :display_error_message
13
+ alias_method :display_error_message, :display_error_message_silent
14
+ end
15
+ end
16
+ end
17
+
18
+ def unstub_rake_exception_handling!
19
+ # Turns Rake exception handling back to normal
20
+ Rake.application.instance_eval do
21
+ class << self
22
+ def display_error_message_silent(exception)
23
+ display_error_message_old(exception)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ namespace :airbrake do
30
+ desc "Verify your gem installation by sending a test exception to the airbrake service"
31
+ task :test => [:environment] do
32
+
33
+ stub_rake_exception_handling!
34
+
35
+ Rails.logger = defined?(ActiveSupport::TaggedLogging) ?
36
+ ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) :
37
+ Logger.new(STDOUT)
38
+
39
+ def wait_for_threads
40
+ # if using multiple threads, we have to wait for
41
+ # them to finish
42
+ if GirlFriday.status.empty?
43
+ Thread.list.each do |thread|
44
+ thread.join unless thread == Thread.current
45
+ end
46
+ else
47
+ GirlFriday.shutdown!
48
+ end
49
+ end
50
+
51
+ # Sets up verbose logging
52
+ Rails.logger.level = Logger::DEBUG
53
+ Airbrake.configure(true) do |config|
54
+ config.logger = Rails.logger
55
+ end
56
+
57
+ # Override Rails exception middleware, so we stop cluttering STDOUT
58
+ # with stack trace from Rails
59
+ class ActionDispatch::DebugExceptions; def call(env); @app.call(env); end; end
60
+ class ActionDispatch::ShowExceptions; def call(env); @app.call(env); end; end
61
+
62
+ require './app/controllers/application_controller'
63
+
64
+ class AirbrakeTestingException < RuntimeError; end
65
+
66
+ # Checks if api_key is set
67
+ unless Airbrake.configuration.api_key
68
+ puts "Airbrake needs an API key configured! Check the README to see how to add it."
69
+ exit
70
+ end
71
+
72
+ # Enables Airbrake reporting on all environments,
73
+ # so we don't have to worry about invoking the task in production
74
+ Airbrake.configuration.development_environments = []
75
+
76
+ puts "Configuration:"
77
+ Airbrake.configuration.to_hash.each do |key, value|
78
+ puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
79
+ end
80
+
81
+ unless defined?(ApplicationController)
82
+ puts "No ApplicationController found"
83
+ exit
84
+ end
85
+
86
+ puts 'Setting up the Controller.'
87
+ class ApplicationController
88
+ # This is to bypass any filters that may prevent access to the action.
89
+ prepend_before_filter :test_airbrake
90
+ def test_airbrake
91
+ puts "Raising '#{exception_class.name}' to simulate application failure."
92
+ raise exception_class.new, "\nTesting airbrake via \"rake airbrake:test\"."\
93
+ " If you can see this, it works."
94
+ end
95
+
96
+ # Ensure we actually have an action to go to.
97
+ def verify; end
98
+
99
+ def exception_class
100
+ exception_name = ENV['EXCEPTION'] || "AirbrakeTestingException"
101
+ Object.const_get(exception_name)
102
+ rescue
103
+ Object.const_set(exception_name, Class.new(Exception))
104
+ end
105
+ end
106
+
107
+ Rails.application.routes.draw do
108
+ get 'verify' => 'application#verify', :as => 'verify', :via => :get
109
+ end
110
+
111
+ puts 'Processing request.'
112
+
113
+ config = Rails.application.config
114
+ protocol = (config.respond_to?(:force_ssl) && config.force_ssl) ? 'https' : 'http'
115
+
116
+ env = Rack::MockRequest.env_for("#{protocol}://www.example.com/verify")
117
+ env['REMOTE_ADDR'] = '127.0.0.1'
118
+
119
+ Rails.application.call(env)
120
+
121
+ wait_for_threads if defined? GirlFriday
122
+
123
+ unstub_rake_exception_handling!
124
+ end
125
+ end
126
+