airbrake 3.1.6 → 11.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake.rb +23 -150
  3. data/lib/airbrake/capistrano.rb +6 -42
  4. data/lib/airbrake/capistrano/capistrano2.rb +40 -0
  5. data/lib/airbrake/capistrano/capistrano3.rb +23 -0
  6. data/lib/airbrake/delayed_job.rb +66 -0
  7. data/lib/airbrake/logger.rb +103 -0
  8. data/lib/airbrake/rack.rb +30 -45
  9. data/lib/airbrake/rack/context_filter.rb +65 -0
  10. data/lib/airbrake/rack/http_headers_filter.rb +44 -0
  11. data/lib/airbrake/rack/http_params_filter.rb +27 -0
  12. data/lib/airbrake/rack/instrumentable.rb +136 -0
  13. data/lib/airbrake/rack/middleware.rb +102 -0
  14. data/lib/airbrake/rack/request_body_filter.rb +33 -0
  15. data/lib/airbrake/rack/request_store.rb +34 -0
  16. data/lib/airbrake/rack/route_filter.rb +51 -0
  17. data/lib/airbrake/rack/session_filter.rb +25 -0
  18. data/lib/airbrake/rack/user.rb +74 -0
  19. data/lib/airbrake/rack/user_filter.rb +25 -0
  20. data/lib/airbrake/rails.rb +25 -31
  21. data/lib/airbrake/rails/action_cable.rb +35 -0
  22. data/lib/airbrake/rails/action_cable/notify_callback.rb +22 -0
  23. data/lib/airbrake/rails/action_controller.rb +40 -0
  24. data/lib/airbrake/rails/action_controller_notify_subscriber.rb +32 -0
  25. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +51 -0
  26. data/lib/airbrake/rails/action_controller_route_subscriber.rb +33 -0
  27. data/lib/airbrake/rails/active_job.rb +50 -0
  28. data/lib/airbrake/rails/active_record.rb +36 -0
  29. data/lib/airbrake/rails/active_record_subscriber.rb +46 -0
  30. data/lib/airbrake/rails/app.rb +78 -0
  31. data/lib/airbrake/rails/backtrace_cleaner.rb +23 -0
  32. data/lib/airbrake/rails/curb.rb +32 -0
  33. data/lib/airbrake/rails/event.rb +81 -0
  34. data/lib/airbrake/rails/excon_subscriber.rb +25 -0
  35. data/lib/airbrake/rails/http.rb +14 -0
  36. data/lib/airbrake/rails/http_client.rb +16 -0
  37. data/lib/airbrake/rails/net_http.rb +18 -0
  38. data/lib/airbrake/rails/railtie.rb +151 -0
  39. data/lib/airbrake/rails/typhoeus.rb +16 -0
  40. data/lib/airbrake/rake.rb +65 -0
  41. data/lib/airbrake/rake/tasks.rb +112 -0
  42. data/lib/airbrake/resque.rb +61 -0
  43. data/lib/airbrake/shoryuken.rb +54 -0
  44. data/lib/airbrake/sidekiq.rb +55 -0
  45. data/lib/airbrake/sidekiq/retryable_jobs_filter.rb +53 -0
  46. data/lib/airbrake/sneakers.rb +72 -0
  47. data/lib/airbrake/version.rb +5 -1
  48. data/lib/generators/airbrake_generator.rb +25 -0
  49. data/lib/generators/airbrake_initializer.rb.erb +80 -0
  50. metadata +206 -259
  51. data/CHANGELOG +0 -944
  52. data/Gemfile +0 -3
  53. data/Guardfile +0 -6
  54. data/INSTALL +0 -20
  55. data/MIT-LICENSE +0 -22
  56. data/README.md +0 -556
  57. data/README_FOR_HEROKU_ADDON.md +0 -94
  58. data/Rakefile +0 -223
  59. data/SUPPORTED_RAILS_VERSIONS +0 -38
  60. data/TESTING.md +0 -41
  61. data/airbrake.gemspec +0 -40
  62. data/bin/airbrake +0 -12
  63. data/features/metal.feature +0 -18
  64. data/features/rack.feature +0 -60
  65. data/features/rails.feature +0 -272
  66. data/features/rails_with_js_notifier.feature +0 -97
  67. data/features/rake.feature +0 -27
  68. data/features/sinatra.feature +0 -29
  69. data/features/step_definitions/file_steps.rb +0 -10
  70. data/features/step_definitions/metal_steps.rb +0 -23
  71. data/features/step_definitions/rack_steps.rb +0 -23
  72. data/features/step_definitions/rails_application_steps.rb +0 -478
  73. data/features/step_definitions/rake_steps.rb +0 -17
  74. data/features/support/airbrake_shim.rb.template +0 -16
  75. data/features/support/env.rb +0 -18
  76. data/features/support/matchers.rb +0 -35
  77. data/features/support/rails.rb +0 -201
  78. data/features/support/rake/Rakefile +0 -68
  79. data/features/support/terminal.rb +0 -107
  80. data/features/user_informer.feature +0 -63
  81. data/generators/airbrake/airbrake_generator.rb +0 -94
  82. data/generators/airbrake/lib/insert_commands.rb +0 -34
  83. data/generators/airbrake/lib/rake_commands.rb +0 -24
  84. data/generators/airbrake/templates/airbrake_tasks.rake +0 -25
  85. data/generators/airbrake/templates/capistrano_hook.rb +0 -6
  86. data/generators/airbrake/templates/initializer.rb +0 -6
  87. data/install.rb +0 -1
  88. data/lib/airbrake/backtrace.rb +0 -108
  89. data/lib/airbrake/cli/client.rb +0 -68
  90. data/lib/airbrake/cli/options.rb +0 -41
  91. data/lib/airbrake/cli/printer.rb +0 -30
  92. data/lib/airbrake/cli/project.rb +0 -17
  93. data/lib/airbrake/cli/project_factory.rb +0 -36
  94. data/lib/airbrake/cli/runner.rb +0 -48
  95. data/lib/airbrake/cli/validator.rb +0 -8
  96. data/lib/airbrake/configuration.rb +0 -311
  97. data/lib/airbrake/extensions/blank.rb +0 -73
  98. data/lib/airbrake/notice.rb +0 -390
  99. data/lib/airbrake/rails/action_controller_catcher.rb +0 -30
  100. data/lib/airbrake/rails/controller_methods.rb +0 -87
  101. data/lib/airbrake/rails/error_lookup.rb +0 -33
  102. data/lib/airbrake/rails/javascript_notifier.rb +0 -47
  103. data/lib/airbrake/rails/middleware/exceptions_catcher.rb +0 -33
  104. data/lib/airbrake/rails3_tasks.rb +0 -98
  105. data/lib/airbrake/railtie.rb +0 -48
  106. data/lib/airbrake/rake_handler.rb +0 -71
  107. data/lib/airbrake/sender.rb +0 -128
  108. data/lib/airbrake/shared_tasks.rb +0 -47
  109. data/lib/airbrake/tasks.rb +0 -83
  110. data/lib/airbrake/user_informer.rb +0 -27
  111. data/lib/airbrake_tasks.rb +0 -64
  112. data/lib/rails/generators/airbrake/airbrake_generator.rb +0 -100
  113. data/lib/templates/javascript_notifier.erb +0 -15
  114. data/lib/templates/rescue.erb +0 -91
  115. data/rails/init.rb +0 -1
  116. data/resources/README.md +0 -34
  117. data/resources/ca-bundle.crt +0 -3376
  118. data/script/integration_test.rb +0 -38
  119. data/test/airbrake_2_3.xsd +0 -88
  120. data/test/airbrake_tasks_test.rb +0 -170
  121. data/test/backtrace_test.rb +0 -162
  122. data/test/capistrano_test.rb +0 -34
  123. data/test/catcher_test.rb +0 -333
  124. data/test/configuration_test.rb +0 -233
  125. data/test/helper.rb +0 -263
  126. data/test/javascript_notifier_test.rb +0 -51
  127. data/test/logger_test.rb +0 -79
  128. data/test/notice_test.rb +0 -490
  129. data/test/notifier_test.rb +0 -276
  130. data/test/rack_test.rb +0 -58
  131. data/test/rails_initializer_test.rb +0 -36
  132. data/test/recursion_test.rb +0 -10
  133. data/test/sender_test.rb +0 -288
  134. data/test/user_informer_test.rb +0 -29
@@ -1,54 +1,39 @@
1
- module Airbrake
2
- # Middleware for Rack applications. Any errors raised by the upstream
3
- # application will be delivered to Airbrake and re-raised.
4
- #
5
- # Synopsis:
6
- #
7
- # require 'rack'
8
- # require 'airbrake'
9
- #
10
- # Airbrake.configure do |config|
11
- # config.api_key = 'my_api_key'
12
- # end
13
- #
14
- # app = Rack::Builder.app do
15
- # run lambda { |env| raise "Rack down" }
16
- # end
17
- #
18
- # use Airbrake::Rack
19
- # run app
20
- #
21
- # Use a standard Airbrake.configure call to configure your api key.
22
- class Rack
23
- def initialize(app)
24
- @app = app
25
- end
1
+ # frozen_string_literal: true
26
2
 
27
- def ignored_user_agent?(env)
28
- true if Airbrake.
29
- configuration.
30
- ignore_user_agent.
31
- flatten.
32
- any? { |ua| ua === env['HTTP_USER_AGENT'] }
33
- end
3
+ require 'airbrake/rack/user'
4
+ require 'airbrake/rack/user_filter'
5
+ require 'airbrake/rack/context_filter'
6
+ require 'airbrake/rack/session_filter'
7
+ require 'airbrake/rack/http_params_filter'
8
+ require 'airbrake/rack/http_headers_filter'
9
+ require 'airbrake/rack/request_body_filter'
10
+ require 'airbrake/rack/route_filter'
11
+ require 'airbrake/rack/middleware'
12
+ require 'airbrake/rack/request_store'
13
+ require 'airbrake/rack/instrumentable'
34
14
 
35
- def notify_airbrake(exception,env)
36
- Airbrake.notify_or_ignore(exception,:rack_env => env) unless ignored_user_agent?(env)
37
- end
15
+ module Airbrake
16
+ # Rack is a namespace for all Rack-related code.
17
+ module Rack
18
+ # @since v9.2.0
19
+ # @api public
20
+ def self.capture_timing(label)
21
+ return yield unless Airbrake::Config.instance.performance_stats
38
22
 
39
- def call(env)
40
- begin
41
- response = @app.call(env)
42
- rescue Exception => raised
43
- env['airbrake.error_id'] = notify_airbrake(raised,env)
44
- raise
45
- end
23
+ routes = Airbrake::Rack::RequestStore[:routes]
24
+ if !routes || routes.none?
25
+ result = yield
26
+ else
27
+ timed_trace = Airbrake::TimedTrace.span(label) do
28
+ result = yield
29
+ end
46
30
 
47
- if env['rack.exception']
48
- env['airbrake.error_id'] = notify_airbrake(env['rack.exception'],env)
31
+ routes.each do |_route_path, params|
32
+ params[:groups].merge!(timed_trace.spans)
33
+ end
49
34
  end
50
35
 
51
- response
36
+ result
52
37
  end
53
38
  end
54
39
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rack
5
+ # Adds context (URL, User-Agent, framework version, controller and more).
6
+ #
7
+ # @since v5.7.0
8
+ class ContextFilter
9
+ # @return [Integer]
10
+ attr_reader :weight
11
+
12
+ def initialize
13
+ @weight = 99
14
+ end
15
+
16
+ # @see Airbrake::FilterChain#refine
17
+ def call(notice)
18
+ return unless (request = notice.stash[:rack_request])
19
+
20
+ context = notice[:context]
21
+
22
+ context[:url] = request.url
23
+ context[:userAddr] =
24
+ if request.respond_to?(:remote_ip)
25
+ request.remote_ip
26
+ else
27
+ request.ip
28
+ end
29
+ context[:userAgent] = request.user_agent
30
+
31
+ add_framework_version(context)
32
+
33
+ controller = request.env['action_controller.instance']
34
+ return unless controller
35
+
36
+ context[:component] = controller.controller_name
37
+ context[:action] = controller.action_name
38
+ end
39
+
40
+ private
41
+
42
+ def add_framework_version(context)
43
+ if context.key?(:versions)
44
+ context[:versions].merge!(framework_version)
45
+ else
46
+ context[:versions] = framework_version
47
+ end
48
+ end
49
+
50
+ def framework_version
51
+ @framework_version ||=
52
+ if defined?(::Rails) && ::Rails.respond_to?(:version)
53
+ { 'rails' => ::Rails.version }
54
+ elsif defined?(::Sinatra)
55
+ { 'sinatra' => Sinatra::VERSION }
56
+ else
57
+ {
58
+ 'rack_version' => ::Rack.version,
59
+ 'rack_release' => ::Rack.release,
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rack
5
+ # Adds HTTP request parameters.
6
+ #
7
+ # @since v5.7.0
8
+ class HttpHeadersFilter
9
+ # @return [Array<String>] the prefixes of the majority of HTTP headers in
10
+ # Rack (some prefixes match the header names for simplicity)
11
+ HTTP_HEADER_PREFIXES = %w[
12
+ HTTP_
13
+ CONTENT_TYPE
14
+ CONTENT_LENGTH
15
+ ].freeze
16
+
17
+ # @return [Integer]
18
+ attr_reader :weight
19
+
20
+ def initialize
21
+ @weight = 98
22
+ end
23
+
24
+ # @see Airbrake::FilterChain#refine
25
+ def call(notice)
26
+ return unless (request = notice.stash[:rack_request])
27
+
28
+ http_headers = request.env.map.with_object({}) do |(key, value), headers|
29
+ if HTTP_HEADER_PREFIXES.any? { |prefix| key.to_s.start_with?(prefix) }
30
+ headers[key] = value
31
+ end
32
+
33
+ headers
34
+ end
35
+
36
+ notice[:context].merge!(
37
+ httpMethod: request.request_method,
38
+ referer: request.referer,
39
+ headers: http_headers,
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rack
5
+ # Adds HTTP request parameters.
6
+ #
7
+ # @since v5.7.0
8
+ class HttpParamsFilter
9
+ # @return [Integer]
10
+ attr_reader :weight
11
+
12
+ def initialize
13
+ @weight = 97
14
+ end
15
+
16
+ # @see Airbrake::FilterChain#refine
17
+ def call(notice)
18
+ return unless (request = notice.stash[:rack_request])
19
+
20
+ notice[:params].merge!(request.params)
21
+
22
+ rails_params = request.env['action_dispatch.request.parameters']
23
+ notice[:params].merge!(rails_params) if rails_params
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rack
5
+ # Instrumentable holds methods that simplify instrumenting Rack apps.
6
+ # @example
7
+ # class UsersController
8
+ # extend Airbrake::Rack::Instrumentable
9
+ #
10
+ # def index
11
+ # # ...
12
+ # end
13
+ # airbrake_capture_timing :index
14
+ # end
15
+ #
16
+ # @api public
17
+ # @since v9.2.0
18
+ module Instrumentable
19
+ def airbrake_capture_timing(method_name, label: method_name.to_s)
20
+ instrumentable = ::Airbrake::Rack::Instrumentable
21
+ if instrumentable.should_prepend?(self, method_name)
22
+ instrumentable.prepend_capture_timing(self, method_name, label)
23
+ else
24
+ instrumentable.chain_capture_timing(self, method_name, label)
25
+ end
26
+ method_name
27
+ end
28
+
29
+ # @api private
30
+ def __airbrake_capture_timing_module__
31
+ # Module used to store prepended wrapper methods, saved as an instance
32
+ # variable so each target class/module gets its own module. This just
33
+ # a convenience to avoid prepending a lot of anonymous modules.
34
+ @__airbrake_capture_timing_module__ ||= ::Module.new
35
+ end
36
+ private :__airbrake_capture_timing_module__
37
+
38
+ # Using api private self methods so they don't get defined in the target
39
+ # class or module, but can still be called by the above method.
40
+
41
+ # @api private
42
+ def self.should_prepend?(klass, method_name)
43
+ # Don't chain already-prepended or operator methods.
44
+ klass.module_exec do
45
+ self_class_idx = ancestors.index(self)
46
+ method_owner_idx = ancestors.index(instance_method(method_name).owner)
47
+ method_owner_idx < self_class_idx || !(/\A\W/ =~ method_name).nil?
48
+ end
49
+ end
50
+
51
+ # @api private
52
+ def self.prepend_capture_timing(klass, method_name, label)
53
+ args = method_signature
54
+ visibility = method_visibility(klass, method_name)
55
+
56
+ # Generate the wrapper method.
57
+ klass.module_exec do
58
+ mod = __airbrake_capture_timing_module__
59
+ mod.module_exec do
60
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
61
+ def #{method_name}(#{args})
62
+ Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
63
+ super
64
+ end
65
+ end
66
+ #{visibility} :#{method_name}
67
+ RUBY
68
+ end
69
+ prepend mod
70
+ end
71
+ end
72
+
73
+ # @api private
74
+ def self.chain_capture_timing(klass, method_name, label)
75
+ args = method_signature
76
+ visibility = method_visibility(klass, method_name)
77
+
78
+ # Generate the wrapper method.
79
+ aliased = method_name.to_s.sub(/([?!=])$/, '')
80
+ punctuation = Regexp.last_match(1)
81
+ wrapped_method_name = "#{aliased}_without_airbrake#{punctuation}"
82
+ needs_removal = method_needs_removal(klass, method_name)
83
+ klass.module_exec do
84
+ alias_method wrapped_method_name, method_name
85
+ remove_method method_name if needs_removal
86
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
87
+ def #{method_name}(#{args})
88
+ Airbrake::Rack.capture_timing(#{label.to_s.inspect}) do
89
+ __send__("#{aliased}_without_airbrake#{punctuation}", #{args})
90
+ end
91
+ end
92
+ #{visibility} :#{method_name}
93
+ RUBY
94
+ end
95
+ end
96
+
97
+ # @api private
98
+ def self.method_visibility(klass, method_name)
99
+ klass.module_exec do
100
+ if protected_method_defined?(method_name)
101
+ "protected"
102
+ elsif private_method_defined?(method_name)
103
+ "private"
104
+ else
105
+ "public"
106
+ end
107
+ end
108
+ end
109
+
110
+ # @api private
111
+ # A method instead of a constant so it isn't accessible in the target.
112
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
113
+ def self.method_signature
114
+ "*args, **kw_args, &block"
115
+ end
116
+ else
117
+ def self.method_signature
118
+ "*args, &block"
119
+ end
120
+ end
121
+
122
+ # @api private
123
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.6")
124
+ def self.method_needs_removal(klass, method_name)
125
+ klass.method_defined?(method_name, false) ||
126
+ klass.private_method_defined?(method_name, false)
127
+ end
128
+ else
129
+ def self.method_needs_removal(klass, method_name)
130
+ klass.instance_methods(false).include?(method_name) ||
131
+ klass.private_instance_methods(false).include?(method_name)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Airbrake
4
+ module Rack
5
+ # Airbrake Rack middleware for Rails and Sinatra applications (or any other
6
+ # Rack-compliant app). Any errors raised by the upstream application will be
7
+ # delivered to Airbrake and re-raised.
8
+ #
9
+ # The middleware automatically sends information about the framework that
10
+ # uses it (name and version).
11
+ #
12
+ # For Rails apps the middleware collects route performance statistics.
13
+ class Middleware
14
+ def initialize(app)
15
+ @app = app
16
+ end
17
+
18
+ # Thread-safe {call!}.
19
+ #
20
+ # @param [Hash] env the Rack environment
21
+ # @see https://github.com/airbrake/airbrake/issues/904
22
+ def call(env)
23
+ dup.call!(env)
24
+ end
25
+
26
+ # Rescues any exceptions, sends them to Airbrake and re-raises the
27
+ # exception. We also duplicate middleware to guarantee thread-safety.
28
+ #
29
+ # @param [Hash] env the Rack environment
30
+ def call!(env)
31
+ before_call(env)
32
+
33
+ begin
34
+ response = @app.call(env)
35
+ rescue Exception => ex # rubocop:disable Lint/RescueException
36
+ notify_airbrake(ex)
37
+ raise ex
38
+ end
39
+
40
+ exception = framework_exception(env)
41
+ notify_airbrake(exception) if exception
42
+
43
+ response
44
+ ensure
45
+ # Clear routes for the next request.
46
+ RequestStore.clear
47
+ end
48
+
49
+ private
50
+
51
+ def before_call(env)
52
+ # Rails hooks such as ActionControllerRouteSubscriber rely on this.
53
+ RequestStore[:routes] = {}
54
+ RequestStore[:request] = find_request(env)
55
+ end
56
+
57
+ def find_request(env)
58
+ if defined?(ActionDispatch::Request)
59
+ ActionDispatch::Request.new(env)
60
+ elsif defined?(Sinatra::Request)
61
+ Sinatra::Request.new(env)
62
+ else
63
+ ::Rack::Request.new(env)
64
+ end
65
+ end
66
+
67
+ def notify_airbrake(exception)
68
+ notice = Airbrake.build_notice(exception)
69
+ return unless notice
70
+
71
+ # ActionDispatch::Request correctly captures server port when using SSL:
72
+ # See: https://github.com/airbrake/airbrake/issues/802
73
+ notice.stash[:rack_request] = RequestStore[:request]
74
+
75
+ Airbrake.notify(notice)
76
+ end
77
+
78
+ # Web framework middlewares often store rescued exceptions inside the
79
+ # Rack env, but Rack doesn't have a standard key for it:
80
+ #
81
+ # - Rails uses action_dispatch.exception: https://goo.gl/Kd694n
82
+ # - Sinatra uses sinatra.error: https://goo.gl/LLkVL9
83
+ # - Goliath uses rack.exception: https://goo.gl/i7e1nA
84
+ def framework_exception(env)
85
+ env['action_dispatch.exception'] ||
86
+ env['sinatra.error'] ||
87
+ env['rack.exception']
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ [
94
+ Airbrake::Rack::ContextFilter,
95
+ Airbrake::Rack::UserFilter,
96
+ Airbrake::Rack::SessionFilter,
97
+ Airbrake::Rack::HttpParamsFilter,
98
+ Airbrake::Rack::HttpHeadersFilter,
99
+ Airbrake::Rack::RouteFilter,
100
+ ].each do |filter|
101
+ Airbrake.add_filter(filter.new)
102
+ end