bugsnag 5.5.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +33 -11
- data/CHANGELOG.md +23 -0
- data/Gemfile +20 -0
- data/Rakefile +19 -12
- data/UPGRADING.md +58 -0
- data/VERSION +1 -1
- data/bugsnag.gemspec +0 -9
- data/lib/bugsnag.rb +64 -86
- data/lib/bugsnag/configuration.rb +42 -26
- data/lib/bugsnag/delivery.rb +9 -0
- data/lib/bugsnag/delivery/synchronous.rb +3 -5
- data/lib/bugsnag/delivery/thread_queue.rb +4 -2
- data/lib/bugsnag/helpers.rb +5 -16
- data/lib/bugsnag/{delayed_job.rb → integrations/delayed_job.rb} +15 -7
- data/lib/bugsnag/{mailman.rb → integrations/mailman.rb} +13 -11
- data/lib/bugsnag/{que.rb → integrations/que.rb} +11 -11
- data/lib/bugsnag/{rack.rb → integrations/rack.rb} +22 -23
- data/lib/bugsnag/{rails → integrations/rails}/active_record_rescue.rb +9 -7
- data/lib/bugsnag/{rails → integrations/rails}/controller_methods.rb +0 -9
- data/lib/bugsnag/{railtie.rb → integrations/railtie.rb} +24 -21
- data/lib/bugsnag/{rake.rb → integrations/rake.rb} +12 -9
- data/lib/bugsnag/{resque.rb → integrations/resque.rb} +12 -9
- data/lib/bugsnag/integrations/shoryuken.rb +49 -0
- data/lib/bugsnag/{sidekiq.rb → integrations/sidekiq.rb} +13 -9
- data/lib/bugsnag/middleware/callbacks.rb +4 -8
- data/lib/bugsnag/middleware/classify_error.rb +7 -13
- data/lib/bugsnag/middleware/clearance_user.rb +8 -8
- data/lib/bugsnag/middleware/exception_meta_data.rb +34 -0
- data/lib/bugsnag/middleware/ignore_error_class.rb +21 -0
- data/lib/bugsnag/middleware/mailman.rb +4 -4
- data/lib/bugsnag/middleware/rack_request.rb +13 -13
- data/lib/bugsnag/middleware/rails3_request.rb +10 -10
- data/lib/bugsnag/middleware/rake.rb +5 -5
- data/lib/bugsnag/middleware/sidekiq.rb +5 -5
- data/lib/bugsnag/middleware/suggestion_data.rb +30 -0
- data/lib/bugsnag/middleware/warden_user.rb +6 -6
- data/lib/bugsnag/middleware_stack.rb +5 -5
- data/lib/bugsnag/report.rb +187 -0
- data/lib/bugsnag/stacktrace.rb +113 -0
- data/lib/bugsnag/tasks/bugsnag.rake +2 -70
- data/spec/cleaner_spec.rb +6 -0
- data/spec/configuration_spec.rb +1 -1
- data/spec/fixtures/middleware/internal_info_setter.rb +3 -3
- data/spec/fixtures/middleware/public_info_setter.rb +3 -3
- data/spec/fixtures/tasks/Rakefile +2 -3
- data/spec/integration_spec.rb +5 -20
- data/spec/{delayed_job_spec.rb → integrations/delayed_job_spec.rb} +0 -0
- data/spec/integrations/sidekiq_spec.rb +34 -0
- data/spec/middleware_spec.rb +108 -35
- data/spec/rack_spec.rb +1 -1
- data/spec/{notification_spec.rb → report_spec.rb} +226 -209
- data/spec/spec_helper.rb +18 -0
- data/spec/{code_spec.rb → stacktrace_spec.rb} +1 -1
- metadata +23 -139
- data/.document +0 -5
- data/lib/bugsnag/capistrano.rb +0 -7
- data/lib/bugsnag/capistrano2.rb +0 -32
- data/lib/bugsnag/delay/resque.rb +0 -21
- data/lib/bugsnag/deploy.rb +0 -35
- data/lib/bugsnag/middleware/rails2_request.rb +0 -52
- data/lib/bugsnag/notification.rb +0 -506
- data/lib/bugsnag/rails.rb +0 -70
- data/lib/bugsnag/rails/action_controller_rescue.rb +0 -74
- data/lib/bugsnag/shoryuken.rb +0 -41
- data/lib/bugsnag/tasks/bugsnag.cap +0 -48
- data/rails/init.rb +0 -7
@@ -4,25 +4,28 @@ Rake::TaskManager.record_task_metadata = true
|
|
4
4
|
|
5
5
|
class Rake::Task
|
6
6
|
|
7
|
+
FRAMEWORK_ATTRIBUTES = {
|
8
|
+
:framework => "Rake"
|
9
|
+
}
|
10
|
+
|
7
11
|
def execute_with_bugsnag(args=nil)
|
8
12
|
Bugsnag.configuration.app_type ||= "rake"
|
9
13
|
old_task = Bugsnag.configuration.request_data[:bugsnag_running_task]
|
10
|
-
Bugsnag.set_request_data :bugsnag_running_task, self
|
14
|
+
Bugsnag.configuration.set_request_data :bugsnag_running_task, self
|
11
15
|
|
12
16
|
execute_without_bugsnag(args)
|
13
17
|
|
14
18
|
rescue Exception => ex
|
15
|
-
Bugsnag.
|
16
|
-
|
17
|
-
|
18
|
-
:
|
19
|
-
|
20
|
-
}
|
19
|
+
Bugsnag.notify(ex, true) do |report|
|
20
|
+
report.severity = "error"
|
21
|
+
report.severity_reason = {
|
22
|
+
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
|
23
|
+
:attributes => FRAMEWORK_ATTRIBUTES
|
21
24
|
}
|
22
|
-
|
25
|
+
end
|
23
26
|
raise
|
24
27
|
ensure
|
25
|
-
Bugsnag.set_request_data :bugsnag_running_task, old_task
|
28
|
+
Bugsnag.configuration.set_request_data :bugsnag_running_task, old_task
|
26
29
|
end
|
27
30
|
|
28
31
|
alias_method :execute_without_bugsnag, :execute
|
@@ -3,6 +3,11 @@ require "resque/failure/multiple"
|
|
3
3
|
|
4
4
|
module Bugsnag
|
5
5
|
class Resque < ::Resque::Failure::Base
|
6
|
+
|
7
|
+
FRAMEWORK_ATTRIBUTES = {
|
8
|
+
:framework => "Resque"
|
9
|
+
}
|
10
|
+
|
6
11
|
def self.configure(&block)
|
7
12
|
add_failure_backend
|
8
13
|
Bugsnag.configure(&block)
|
@@ -26,16 +31,14 @@ module Bugsnag
|
|
26
31
|
end
|
27
32
|
|
28
33
|
def save
|
29
|
-
Bugsnag.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
:
|
34
|
-
:attributes => {
|
35
|
-
:framework => "Resque"
|
36
|
-
}
|
34
|
+
Bugsnag.notify(exception, true) do |report|
|
35
|
+
report.severity = "error"
|
36
|
+
report.severity_reason = {
|
37
|
+
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
|
38
|
+
:attributes => FRAMEWORK_ATTRIBUTES
|
37
39
|
}
|
38
|
-
|
40
|
+
report.meta_data.merge!({:context => "#{payload['class']}@#{queue}", :payload => payload})
|
41
|
+
end
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'shoryuken'
|
2
|
+
|
3
|
+
module Bugsnag
|
4
|
+
class Shoryuken
|
5
|
+
|
6
|
+
FRAMEWORK_ATTRIBUTES = {
|
7
|
+
:framework => "Shoryuken"
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
Bugsnag.configure do |config|
|
12
|
+
config.app_type ||= "shoryuken"
|
13
|
+
config.default_delivery_method = :synchronous
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(_, queue, _, body)
|
18
|
+
begin
|
19
|
+
Bugsnag.before_notify_callbacks << lambda {|report|
|
20
|
+
report.add_tab(:shoryuken, {
|
21
|
+
queue: queue,
|
22
|
+
body: body
|
23
|
+
})
|
24
|
+
}
|
25
|
+
|
26
|
+
yield
|
27
|
+
rescue Exception => ex
|
28
|
+
unless [Interrupt, SystemExit, SignalException].include?(ex.class)
|
29
|
+
Bugsnag.auto_notify(ex, true) do |report|
|
30
|
+
report.severity = "error"
|
31
|
+
report.severity_reason = {
|
32
|
+
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
|
33
|
+
:attributes => Bugsnag::Shoryuken::FRAMEWORK_ATTRIBUTES
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
raise
|
38
|
+
ensure
|
39
|
+
Bugsnag.configuration.clear_request_data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
::Shoryuken.configure_server do |config|
|
46
|
+
config.server_middleware do |chain|
|
47
|
+
chain.add ::Bugsnag::Shoryuken
|
48
|
+
end
|
49
|
+
end
|
@@ -2,6 +2,11 @@ require 'sidekiq'
|
|
2
2
|
|
3
3
|
module Bugsnag
|
4
4
|
class Sidekiq
|
5
|
+
|
6
|
+
FRAMEWORK_ATTRIBUTES = {
|
7
|
+
:framework => "Sidekiq"
|
8
|
+
}
|
9
|
+
|
5
10
|
def initialize
|
6
11
|
Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Sidekiq)
|
7
12
|
Bugsnag.configuration.app_type = "sidekiq"
|
@@ -11,22 +16,21 @@ module Bugsnag
|
|
11
16
|
def call(worker, msg, queue)
|
12
17
|
begin
|
13
18
|
# store msg/queue in thread local state to be read by Bugsnag::Middleware::Sidekiq
|
14
|
-
Bugsnag.set_request_data :sidekiq, { :msg => msg, :queue => queue }
|
19
|
+
Bugsnag.configuration.set_request_data :sidekiq, { :msg => msg, :queue => queue }
|
15
20
|
|
16
21
|
yield
|
17
22
|
rescue Exception => ex
|
18
23
|
raise ex if [Interrupt, SystemExit, SignalException].include? ex.class
|
19
|
-
Bugsnag.
|
20
|
-
|
21
|
-
|
22
|
-
:
|
23
|
-
|
24
|
-
}
|
24
|
+
Bugsnag.notify(ex, true) do |report|
|
25
|
+
report.severity = "error"
|
26
|
+
report.severity_reason = {
|
27
|
+
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
|
28
|
+
:attributes => FRAMEWORK_ATTRIBUTES
|
25
29
|
}
|
26
|
-
|
30
|
+
end
|
27
31
|
raise
|
28
32
|
ensure
|
29
|
-
Bugsnag.clear_request_data
|
33
|
+
Bugsnag.configuration.clear_request_data
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -4,16 +4,12 @@ module Bugsnag::Middleware
|
|
4
4
|
@bugsnag = bugsnag
|
5
5
|
end
|
6
6
|
|
7
|
-
def call(
|
8
|
-
if
|
9
|
-
|
7
|
+
def call(report)
|
8
|
+
if report.request_data[:before_callbacks]
|
9
|
+
report.request_data[:before_callbacks].each {|c| c.call(*[report][0...c.arity]) }
|
10
10
|
end
|
11
11
|
|
12
|
-
@bugsnag.call(
|
13
|
-
|
14
|
-
if notification.request_data[:after_callbacks]
|
15
|
-
notification.request_data[:after_callbacks].each {|c| c.call(*[notification][0...c.arity]) }
|
16
|
-
end
|
12
|
+
@bugsnag.call(report)
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
@@ -18,36 +18,30 @@ module Bugsnag::Middleware
|
|
18
18
|
@bugsnag = bugsnag
|
19
19
|
end
|
20
20
|
|
21
|
-
def call(
|
22
|
-
|
23
|
-
|
24
|
-
outer_break = false
|
21
|
+
def call(report)
|
22
|
+
report.raw_exceptions.each do |ex|
|
25
23
|
|
26
24
|
ancestor_chain = ex.class.ancestors.select {
|
27
|
-
|ancestor| ancestor.is_a?(Class)
|
25
|
+
|ancestor| ancestor.is_a?(Class)
|
28
26
|
}.map {
|
29
27
|
|ancestor| ancestor.to_s
|
30
28
|
}
|
31
29
|
|
32
30
|
INFO_CLASSES.each do |info_class|
|
33
31
|
if ancestor_chain.include?(info_class)
|
34
|
-
|
35
|
-
:type => Bugsnag::
|
32
|
+
report.severity_reason = {
|
33
|
+
:type => Bugsnag::Report::ERROR_CLASS,
|
36
34
|
:attributes => {
|
37
35
|
:errorClass => info_class
|
38
36
|
}
|
39
37
|
}
|
40
|
-
|
41
|
-
outer_break = true
|
38
|
+
report.severity = 'info'
|
42
39
|
break
|
43
40
|
end
|
44
41
|
end
|
45
|
-
|
46
|
-
break if outer_break
|
47
42
|
end
|
48
43
|
|
49
|
-
@bugsnag.call(
|
44
|
+
@bugsnag.call(report)
|
50
45
|
end
|
51
46
|
end
|
52
47
|
end
|
53
|
-
|
@@ -6,15 +6,15 @@ module Bugsnag::Middleware
|
|
6
6
|
@bugsnag = bugsnag
|
7
7
|
end
|
8
8
|
|
9
|
-
def call(
|
10
|
-
if
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
def call(report)
|
10
|
+
if report.request_data[:rack_env] &&
|
11
|
+
report.request_data[:rack_env]["clearance"] &&
|
12
|
+
report.request_data[:rack_env]["clearance"].signed_in? &&
|
13
|
+
report.request_data[:rack_env]["clearance"].current_user
|
14
14
|
|
15
15
|
# Extract useful user information
|
16
16
|
user = {}
|
17
|
-
user_object =
|
17
|
+
user_object = report.request_data[:rack_env]["clearance"].current_user
|
18
18
|
if user_object
|
19
19
|
# Build the bugsnag user info from the current user record
|
20
20
|
COMMON_USER_FIELDS.each do |field|
|
@@ -22,10 +22,10 @@ module Bugsnag::Middleware
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
report.user = user unless user.empty?
|
26
26
|
end
|
27
27
|
|
28
|
-
@bugsnag.call(
|
28
|
+
@bugsnag.call(report)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Bugsnag::Middleware
|
2
|
+
class ExceptionMetaData
|
3
|
+
def initialize(bugsnag)
|
4
|
+
@bugsnag = bugsnag
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(report)
|
8
|
+
# Apply the user's information attached to the exceptions
|
9
|
+
report.raw_exceptions.each do |exception|
|
10
|
+
if exception.class.include?(Bugsnag::MetaData)
|
11
|
+
if exception.bugsnag_user_id.is_a?(String)
|
12
|
+
report.user = {id: exception.bugsnag_user_id}
|
13
|
+
end
|
14
|
+
|
15
|
+
if exception.bugsnag_context.is_a?(String)
|
16
|
+
report.context = exception.bugsnag_context
|
17
|
+
end
|
18
|
+
|
19
|
+
if exception.bugsnag_grouping_hash.is_a?(String)
|
20
|
+
report.grouping_hash = exception.bugsnag_grouping_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
if exception.respond_to?(:bugsnag_meta_data) && exception.bugsnag_meta_data
|
24
|
+
exception.bugsnag_meta_data.each do |key, value|
|
25
|
+
report.add_tab key, value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@bugsnag.call(report)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bugsnag::Middleware
|
2
|
+
class IgnoreErrorClass
|
3
|
+
def initialize(bugsnag)
|
4
|
+
@bugsnag = bugsnag
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(report)
|
8
|
+
ignore_error_class = report.raw_exceptions.any? do |ex|
|
9
|
+
ancestor_chain = ex.class.ancestors.select { |ancestor| ancestor.is_a?(Class) }.to_set
|
10
|
+
|
11
|
+
report.configuration.ignore_classes.any? do |to_ignore|
|
12
|
+
to_ignore.is_a?(Proc) ? to_ignore.call(ex) : ancestor_chain.include?(to_ignore)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
report.ignore! if ignore_error_class
|
17
|
+
|
18
|
+
@bugsnag.call(report)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -4,10 +4,10 @@ module Bugsnag::Middleware
|
|
4
4
|
@bugsnag = bugsnag
|
5
5
|
end
|
6
6
|
|
7
|
-
def call(
|
8
|
-
mailman_msg =
|
9
|
-
|
10
|
-
@bugsnag.call(
|
7
|
+
def call(report)
|
8
|
+
mailman_msg = report.request_data[:mailman_msg]
|
9
|
+
report.add_tab(:mailman, {"message" => mailman_msg}) if mailman_msg
|
10
|
+
@bugsnag.call(report)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -6,9 +6,9 @@ module Bugsnag::Middleware
|
|
6
6
|
@bugsnag = bugsnag
|
7
7
|
end
|
8
8
|
|
9
|
-
def call(
|
10
|
-
if
|
11
|
-
env =
|
9
|
+
def call(report)
|
10
|
+
if report.request_data[:rack_env]
|
11
|
+
env = report.request_data[:rack_env]
|
12
12
|
|
13
13
|
request = ::Rack::Request.new(env)
|
14
14
|
|
@@ -17,10 +17,10 @@ module Bugsnag::Middleware
|
|
17
17
|
session = env["rack.session"]
|
18
18
|
|
19
19
|
# Set the context
|
20
|
-
|
20
|
+
report.context = "#{request.request_method} #{request.path}"
|
21
21
|
|
22
22
|
# Set a sensible default for user_id
|
23
|
-
|
23
|
+
report.user["id"] = request.ip
|
24
24
|
|
25
25
|
# Build the clean url (hide the port if it is obvious)
|
26
26
|
url = "#{request.scheme}://#{request.host}"
|
@@ -28,9 +28,9 @@ module Bugsnag::Middleware
|
|
28
28
|
|
29
29
|
# If app is passed a bad URL, this code will crash attempting to clean it
|
30
30
|
begin
|
31
|
-
url << Bugsnag::Cleaner.new(
|
31
|
+
url << Bugsnag::Cleaner.new(report.configuration.meta_data_filters).clean_url(request.fullpath)
|
32
32
|
rescue StandardError => stde
|
33
|
-
Bugsnag.
|
33
|
+
Bugsnag.configuration.warn "RackRequest - Rescued error while cleaning request.fullpath: #{stde}"
|
34
34
|
end
|
35
35
|
|
36
36
|
headers = {}
|
@@ -48,7 +48,7 @@ module Bugsnag::Middleware
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Add a request tab
|
51
|
-
|
51
|
+
report.add_tab(:request, {
|
52
52
|
:url => url,
|
53
53
|
:httpMethod => request.request_method,
|
54
54
|
:params => params.to_hash,
|
@@ -58,23 +58,23 @@ module Bugsnag::Middleware
|
|
58
58
|
})
|
59
59
|
|
60
60
|
# Add an environment tab
|
61
|
-
if
|
62
|
-
|
61
|
+
if report.configuration.send_environment
|
62
|
+
report.add_tab(:environment, env)
|
63
63
|
end
|
64
64
|
|
65
65
|
# Add a session tab
|
66
66
|
if session
|
67
67
|
if session.is_a?(Hash)
|
68
68
|
# Rails 3
|
69
|
-
|
69
|
+
report.add_tab(:session, session)
|
70
70
|
elsif session.respond_to?(:to_hash)
|
71
71
|
# Rails 4
|
72
|
-
|
72
|
+
report.add_tab(:session, session.to_hash)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
@bugsnag.call(
|
77
|
+
@bugsnag.call(report)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -6,40 +6,40 @@ module Bugsnag::Middleware
|
|
6
6
|
@bugsnag = bugsnag
|
7
7
|
end
|
8
8
|
|
9
|
-
def call(
|
10
|
-
if
|
11
|
-
env =
|
9
|
+
def call(report)
|
10
|
+
if report.request_data[:rack_env]
|
11
|
+
env = report.request_data[:rack_env]
|
12
12
|
params = env["action_dispatch.request.parameters"]
|
13
13
|
client_ip = env["action_dispatch.remote_ip"].to_s rescue SPOOF
|
14
14
|
|
15
15
|
if params
|
16
16
|
# Set the context
|
17
|
-
|
17
|
+
report.context = "#{params[:controller]}##{params[:action]}"
|
18
18
|
|
19
19
|
# Augment the request tab
|
20
|
-
|
20
|
+
report.add_tab(:request, {
|
21
21
|
:railsAction => "#{params[:controller]}##{params[:action]}",
|
22
22
|
:params => params
|
23
23
|
})
|
24
24
|
end
|
25
25
|
|
26
26
|
# Use action_dispatch.remote_ip for IP address fields and send request id
|
27
|
-
|
27
|
+
report.add_tab(:request, {
|
28
28
|
:clientIp => client_ip,
|
29
29
|
:requestId => env["action_dispatch.request_id"]
|
30
30
|
})
|
31
31
|
|
32
|
-
|
32
|
+
report.user["id"] = client_ip
|
33
33
|
|
34
34
|
# Add the rails version
|
35
|
-
if
|
36
|
-
|
35
|
+
if report.configuration.send_environment
|
36
|
+
report.add_tab(:environment, {
|
37
37
|
:railsVersion => Rails::VERSION::STRING
|
38
38
|
})
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
@bugsnag.call(
|
42
|
+
@bugsnag.call(report)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|