exception_handling 2.17.0.pre.tstarck.1 → 3.0.0.pre.2
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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.tool-versions +1 -1
- data/Appraisals +0 -6
- data/CHANGELOG.md +8 -7
- data/Gemfile +1 -3
- data/Gemfile.lock +47 -125
- data/README.md +2 -39
- data/exception_handling.gemspec +3 -9
- data/gemfiles/rails_5.gemfile +1 -3
- data/gemfiles/rails_6.gemfile +1 -3
- data/gemfiles/rails_7.gemfile +1 -3
- data/lib/exception_handling/logging_methods.rb +1 -7
- data/lib/exception_handling/testing.rb +0 -13
- data/lib/exception_handling/version.rb +1 -1
- data/lib/exception_handling.rb +30 -221
- data/spec/spec_helper.rb +9 -42
- data/spec/unit/exception_handling/escalate_callback_spec.rb +2 -2
- data/spec/unit/exception_handling_spec.rb +28 -430
- metadata +6 -75
- data/lib/exception_handling/mailer.rb +0 -70
- data/lib/exception_handling/methods.rb +0 -54
- data/lib/exception_handling/sensu.rb +0 -28
- data/spec/unit/exception_handling/mailer_spec.rb +0 -97
- data/spec/unit/exception_handling/methods_spec.rb +0 -105
- data/spec/unit/exception_handling/sensu_spec.rb +0 -51
- data/views/exception_handling/mailer/escalate_custom.html.erb +0 -17
- data/views/exception_handling/mailer/escalation_notification.html.erb +0 -17
- data/views/exception_handling/mailer/log_parser_exception_notification.html.erb +0 -82
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'action_mailer'
|
4
|
-
|
5
|
-
module ExceptionHandling
|
6
|
-
class Mailer < ActionMailer::Base
|
7
|
-
default content_type: "text/html"
|
8
|
-
|
9
|
-
append_view_path "#{File.dirname(__FILE__)}/../../views"
|
10
|
-
|
11
|
-
[:email_environment, :server_name, :sender_address, :exception_recipients, :escalation_recipients].each do |method|
|
12
|
-
define_method method do
|
13
|
-
ExceptionHandling.send(method) or raise "No #{method} set!"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def email_prefix
|
18
|
-
"#{email_environment} exception: "
|
19
|
-
end
|
20
|
-
|
21
|
-
class << self
|
22
|
-
def reloadable?
|
23
|
-
false
|
24
|
-
end
|
25
|
-
|
26
|
-
def mailer_method_category
|
27
|
-
{
|
28
|
-
log_parser_exception_notification: :NetworkOptout
|
29
|
-
}
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def escalation_notification(summary, data, custom_recipients = nil)
|
34
|
-
subject = "#{email_environment} Escalation: #{summary}"
|
35
|
-
from = sender_address.gsub('xception', 'scalation')
|
36
|
-
recipients = begin
|
37
|
-
custom_recipients || escalation_recipients
|
38
|
-
rescue
|
39
|
-
exception_recipients
|
40
|
-
end
|
41
|
-
|
42
|
-
@summary = summary
|
43
|
-
@server = ExceptionHandling.server_name
|
44
|
-
@cleaned_data = data
|
45
|
-
|
46
|
-
mail(from: from,
|
47
|
-
to: recipients,
|
48
|
-
subject: subject)
|
49
|
-
end
|
50
|
-
|
51
|
-
def log_parser_exception_notification(cleaned_data, key)
|
52
|
-
if cleaned_data.is_a?(Hash)
|
53
|
-
cleaned_data = cleaned_data.symbolize_keys
|
54
|
-
local_subject = cleaned_data[:error]
|
55
|
-
else
|
56
|
-
local_subject = "#{key}: #{cleaned_data}"
|
57
|
-
cleaned_data = { error: cleaned_data.to_s }
|
58
|
-
end
|
59
|
-
|
60
|
-
@subject = "#{email_prefix}#{local_subject}"[0, 300]
|
61
|
-
@recipients = exception_recipients
|
62
|
-
from = sender_address
|
63
|
-
@cleaned_data = cleaned_data
|
64
|
-
|
65
|
-
mail(from: from,
|
66
|
-
to: @recipients,
|
67
|
-
subject: @subject)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/concern'
|
4
|
-
require_relative 'logging_methods'
|
5
|
-
|
6
|
-
module ExceptionHandling
|
7
|
-
module Methods # included on models and controllers
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
include ExceptionHandling::LoggingMethods
|
10
|
-
|
11
|
-
protected
|
12
|
-
|
13
|
-
def long_controller_action_timeout
|
14
|
-
if defined?(Rails) && Rails.respond_to?(:env) && Rails.env == 'test'
|
15
|
-
300
|
16
|
-
else
|
17
|
-
30
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def set_current_controller
|
22
|
-
ExceptionHandling.current_controller = self
|
23
|
-
result = nil
|
24
|
-
time = Benchmark.measure do
|
25
|
-
result = yield
|
26
|
-
end
|
27
|
-
if time.real > long_controller_action_timeout && !['development', 'test'].include?(ExceptionHandling.email_environment)
|
28
|
-
name = begin
|
29
|
-
" in #{controller_name}::#{action_name}"
|
30
|
-
rescue
|
31
|
-
" "
|
32
|
-
end
|
33
|
-
log_error("Long controller action detected#{name} %.4fs " % time.real)
|
34
|
-
end
|
35
|
-
result
|
36
|
-
ensure
|
37
|
-
ExceptionHandling.current_controller = nil
|
38
|
-
end
|
39
|
-
|
40
|
-
included do
|
41
|
-
Deprecation3_0.deprecation_warning('ExceptionHandling::Methods', 'include LoggingMethods; in controllers, set your own around_filter to set logging context')
|
42
|
-
if respond_to? :around_filter
|
43
|
-
around_filter :set_current_controller
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class_methods do
|
48
|
-
def set_long_controller_action_timeout(timeout)
|
49
|
-
define_method(:long_controller_action_timeout) { timeout }
|
50
|
-
protected :long_controller_action_timeout
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "socket"
|
4
|
-
|
5
|
-
module ExceptionHandling
|
6
|
-
module Sensu
|
7
|
-
LEVELS = {
|
8
|
-
warning: 1,
|
9
|
-
critical: 2
|
10
|
-
}.freeze
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def generate_event(name, message, level = :warning)
|
14
|
-
status = LEVELS[level] or raise "Invalid alert level #{level}"
|
15
|
-
|
16
|
-
event = { name: ExceptionHandling.sensu_prefix.to_s + name, output: message, status: status }
|
17
|
-
|
18
|
-
send_event(event)
|
19
|
-
end
|
20
|
-
|
21
|
-
def send_event(event)
|
22
|
-
Socket.tcp(ExceptionHandling.sensu_host, ExceptionHandling.sensu_port) do |sock|
|
23
|
-
sock.send(event.to_json, 0)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require File.expand_path('../../spec_helper', __dir__)
|
4
|
-
require 'rails-dom-testing'
|
5
|
-
|
6
|
-
module ExceptionHandling
|
7
|
-
describe Mailer do
|
8
|
-
|
9
|
-
include ::Rails::Dom::Testing::Assertions::SelectorAssertions
|
10
|
-
|
11
|
-
def dont_stub_log_error
|
12
|
-
true
|
13
|
-
end
|
14
|
-
|
15
|
-
context "ExceptionHandling::Mailer" do
|
16
|
-
before do
|
17
|
-
ExceptionHandling.email_environment = 'Test'
|
18
|
-
ExceptionHandling.sender_address = %("Test Exception Mailer" <null_exception@invoca.com>)
|
19
|
-
ExceptionHandling.exception_recipients = ['test_exception@invoca.com']
|
20
|
-
ExceptionHandling.escalation_recipients = ['test_escalation@invoca.com']
|
21
|
-
end
|
22
|
-
|
23
|
-
context "log_parser_exception_notification" do
|
24
|
-
it "send with string" do
|
25
|
-
result = ExceptionHandling::Mailer.log_parser_exception_notification("This is my fake error", "My Fake Subj").deliver_now
|
26
|
-
expect(result.subject).to eq("Test exception: My Fake Subj: This is my fake error")
|
27
|
-
expect(result.body.to_s).to match(/This is my fake error/)
|
28
|
-
assert_emails 1
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "escalation_notification" do
|
33
|
-
before do
|
34
|
-
def document_root_element
|
35
|
-
@body_html.root
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it "send all the information" do
|
40
|
-
ExceptionHandling.email_environment = 'Staging Full'
|
41
|
-
ExceptionHandling.server_name = 'test-fe3'
|
42
|
-
|
43
|
-
ExceptionHandling::Mailer.escalation_notification("Your Favorite <b>Feature<b> Failed", error_string: "It failed because of an error\n <i>More Info<i>", timestamp: 1234567).deliver_now
|
44
|
-
|
45
|
-
assert_emails 1
|
46
|
-
result = ActionMailer::Base.deliveries.last
|
47
|
-
@body_html = Nokogiri::HTML(result.body.to_s)
|
48
|
-
assert_equal_with_diff ['test_escalation@invoca.com'], result.to
|
49
|
-
expect(result[:from].formatted).to eq(["Test Escalation Mailer <null_escalation@invoca.com>"])
|
50
|
-
expect(result.subject).to eq("Staging Full Escalation: Your Favorite <b>Feature<b> Failed")
|
51
|
-
assert_select "title", "Exception Escalation"
|
52
|
-
assert_select "html" do
|
53
|
-
assert_select "body br", { count: 4 }, result.body.to_s # plus 1 for the multiline summary
|
54
|
-
assert_select "body h3", "Your Favorite <b>Feature<b> Failed", result.body.to_s
|
55
|
-
assert_select "body", /1234567/
|
56
|
-
assert_select "body", /It failed because of an error/
|
57
|
-
assert_select "body", /\n <i>More Info<i>/
|
58
|
-
assert_select "body", /test-fe3/
|
59
|
-
# assert_select "body", /#{Web::Application::GIT_REVISION}/
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
it "use defaults for missing fields" do
|
64
|
-
result = ExceptionHandling::Mailer.escalation_notification("Your Favorite Feature Failed", error_string: "It failed because of an error\n More Info")
|
65
|
-
@body_html = Nokogiri::HTML(result.body.to_s)
|
66
|
-
|
67
|
-
assert_equal_with_diff ['test_escalation@invoca.com'], result.to
|
68
|
-
expect(result.from).to eq(["null_escalation@invoca.com"])
|
69
|
-
expect(result.subject).to eq('Test Escalation: Your Favorite Feature Failed')
|
70
|
-
assert_select "html" do
|
71
|
-
assert_select "body i", true, result.body.to_s do |is|
|
72
|
-
assert_select is, "i", 'no error #'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "ExceptionHandling.escalate_to_production_support" do
|
78
|
-
before do
|
79
|
-
Time.now_override = Time.parse('1986-5-21 4:17 am UTC')
|
80
|
-
end
|
81
|
-
|
82
|
-
it "notify production support" do
|
83
|
-
subject = "Runtime Error found!"
|
84
|
-
exception = RuntimeError.new("Test")
|
85
|
-
recipients = ["prodsupport@example.com"]
|
86
|
-
|
87
|
-
ExceptionHandling.production_support_recipients = recipients
|
88
|
-
ExceptionHandling.last_exception_timestamp = Time.now.to_i
|
89
|
-
|
90
|
-
expect(ExceptionHandling).to receive(:escalate).with(subject, exception, Time.now.to_i, recipients)
|
91
|
-
ExceptionHandling.escalate_to_production_support(exception, subject)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require File.expand_path('../../spec_helper', __dir__)
|
4
|
-
|
5
|
-
require "exception_handling/testing"
|
6
|
-
require_relative '../../helpers/exception_helpers.rb'
|
7
|
-
|
8
|
-
module ExceptionHandling
|
9
|
-
describe Methods do
|
10
|
-
include ExceptionHelpers
|
11
|
-
|
12
|
-
def dont_stub_log_error
|
13
|
-
true
|
14
|
-
end
|
15
|
-
|
16
|
-
context "ExceptionHandling::Methods" do
|
17
|
-
before do
|
18
|
-
@controller = Testing::MethodsControllerStub.new
|
19
|
-
ExceptionHandling.stub_handler = nil
|
20
|
-
end
|
21
|
-
|
22
|
-
it "set the around filter" do
|
23
|
-
expect(Testing::MethodsControllerStub.around_filter_method).to eq(:set_current_controller)
|
24
|
-
expect(ExceptionHandling.current_controller).to be_nil
|
25
|
-
@controller.simulate_around_filter do
|
26
|
-
expect(ExceptionHandling.current_controller).to eq(@controller)
|
27
|
-
end
|
28
|
-
expect(ExceptionHandling.current_controller).to be_nil
|
29
|
-
end
|
30
|
-
|
31
|
-
it "use the current_controller when available" do
|
32
|
-
capture_notifications
|
33
|
-
|
34
|
-
expect(ExceptionHandling.logger).to receive(:fatal).with(/blah/, any_args).at_least(:once)
|
35
|
-
@controller.simulate_around_filter do
|
36
|
-
ExceptionHandling.log_error(ArgumentError.new("blah"))
|
37
|
-
expect(sent_notifications.size).to eq(1)
|
38
|
-
expect(/#{Regexp.new(Regexp.escape(@controller.request.request_uri))}/).to match(sent_notifications.last.enhanced_data['request'].to_s)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
it "report long running controller action" do
|
43
|
-
expect(@controller.send(:long_controller_action_timeout)).to eq(2)
|
44
|
-
expect(ExceptionHandling).to receive(:log_error).with(/Long controller action detected in #{@controller.class.name.split("::").last}::test_action/)
|
45
|
-
@controller.simulate_around_filter do
|
46
|
-
sleep(3)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
it "not report long running controller actions if it is less than the timeout" do
|
51
|
-
expect(@controller.send(:long_controller_action_timeout)).to eq(2)
|
52
|
-
allow(ExceptionHandling).to receive(:log_error).and_return("Should not timeout")
|
53
|
-
@controller.simulate_around_filter do
|
54
|
-
sleep(1)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
it "default long running controller action(300/30 for test/prod)" do
|
59
|
-
class DummyController
|
60
|
-
include ExceptionHandling::Methods
|
61
|
-
end
|
62
|
-
|
63
|
-
controller = DummyController.new
|
64
|
-
|
65
|
-
Rails.env = 'production'
|
66
|
-
expect(controller.send(:long_controller_action_timeout)).to eq(30)
|
67
|
-
|
68
|
-
Rails.env = 'test'
|
69
|
-
expect(controller.send(:long_controller_action_timeout)).to eq(300)
|
70
|
-
end
|
71
|
-
|
72
|
-
context "#log_warning" do
|
73
|
-
it "be available to the controller" do
|
74
|
-
expect(@controller.methods.include?(:log_warning)).to eq(true)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "included deprecation" do
|
79
|
-
before do
|
80
|
-
mock_deprecation_3_0
|
81
|
-
end
|
82
|
-
|
83
|
-
it "deprecate when no around_filter in included hook" do
|
84
|
-
k = Class.new
|
85
|
-
k.include ExceptionHandling::Methods
|
86
|
-
end
|
87
|
-
|
88
|
-
it "deprecate controller around_filter in included hook" do
|
89
|
-
controller = Class.new
|
90
|
-
class << controller
|
91
|
-
def around_filter(*)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
controller.include ExceptionHandling::Methods
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def mock_deprecation_3_0
|
101
|
-
expect(STDERR).to receive(:puts).with(/DEPRECATION WARNING: ExceptionHandling::Methods is deprecated and will be removed from exception_handling 3\.0/)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require File.expand_path('../../spec_helper', __dir__)
|
4
|
-
|
5
|
-
module ExceptionHandling
|
6
|
-
describe Sensu do
|
7
|
-
context "#generate_event" do
|
8
|
-
it "create an event" do
|
9
|
-
expect(ExceptionHandling::Sensu).to receive(:send_event).with({ name: "world_is_ending", output: "stick head between knees and kiss ass goodbye", status: 1 })
|
10
|
-
|
11
|
-
ExceptionHandling::Sensu.generate_event("world_is_ending", "stick head between knees and kiss ass goodbye")
|
12
|
-
end
|
13
|
-
|
14
|
-
it "add the sensu prefix" do
|
15
|
-
ExceptionHandling.sensu_prefix = "cnn_"
|
16
|
-
|
17
|
-
expect(ExceptionHandling::Sensu).to receive(:send_event).with({ name: "cnn_world_is_ending", output: "stick head between knees and kiss ass goodbye", status: 1 })
|
18
|
-
|
19
|
-
ExceptionHandling::Sensu.generate_event("world_is_ending", "stick head between knees and kiss ass goodbye")
|
20
|
-
end
|
21
|
-
|
22
|
-
it "allow the level to be set to critical" do
|
23
|
-
expect(ExceptionHandling::Sensu).to receive(:send_event).with({ name: "world_is_ending", output: "stick head between knees and kiss ass goodbye", status: 2 })
|
24
|
-
|
25
|
-
ExceptionHandling::Sensu.generate_event("world_is_ending", "stick head between knees and kiss ass goodbye", :critical)
|
26
|
-
end
|
27
|
-
|
28
|
-
it "error if an invalid level is supplied" do
|
29
|
-
expect(ExceptionHandling::Sensu).to_not receive(:send_event)
|
30
|
-
|
31
|
-
expect do
|
32
|
-
ExceptionHandling::Sensu.generate_event("world_is_ending", "stick head between knees and kiss ass goodbye", :hair_on_fire)
|
33
|
-
end.to raise_exception(RuntimeError, /Invalid alert level/)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "#send_event" do
|
38
|
-
before do
|
39
|
-
@event = { name: "world_is_ending", output: "stick head between knees and kiss ass goodbye", status: 1 }
|
40
|
-
@socket = SocketStub.new
|
41
|
-
end
|
42
|
-
|
43
|
-
it "send event json to sensu client" do
|
44
|
-
expect_any_instance_of(Addrinfo).to receive(:connect).with(any_args) { @socket }
|
45
|
-
ExceptionHandling::Sensu.send_event(@event)
|
46
|
-
|
47
|
-
expect(@socket.sent.first).to eq(@event.to_json)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
-
<head>
|
5
|
-
<title>Exception Escalation</title>
|
6
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<h3><%=h @summary %></h3>
|
10
|
-
<b>Error #:</b> <%= h(@cleaned_data[:timestamp]).presence || '<i>no error #</i>'.html_safe -%><br />
|
11
|
-
<b>Exception:</b> <%= h(@cleaned_data[:error_string]).gsub("\n","<br/>\n").gsub(/ {2,}/) { |spaces| ' '*spaces.size }.html_safe %><br />
|
12
|
-
<b>Server:</b> <%= h(@server).presence || '<i>hostname not set</i>'.html_safe -%><br />
|
13
|
-
<% if @cleaned_data[:scm_revision] %>
|
14
|
-
<b>Revision:</b> <%= @cleaned_data[:scm_revision] %><br />
|
15
|
-
<% end %>
|
16
|
-
</body>
|
17
|
-
</html>
|
@@ -1,17 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
-
<head>
|
5
|
-
<title>Exception Escalation</title>
|
6
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<h3><%=h @summary %></h3>
|
10
|
-
<b>Error #:</b> <%= h(@cleaned_data[:timestamp]).presence || '<i>no error #</i>'.html_safe -%><br />
|
11
|
-
<b>Exception:</b> <%= h(@cleaned_data[:error_string]).gsub("\n","<br/>\n").gsub(/ {2,}/) { |spaces| ' '*spaces.size }.html_safe %><br />
|
12
|
-
<b>Server:</b> <%= h(@server).presence || '<i>hostname not set</i>'.html_safe -%><br />
|
13
|
-
<% if @cleaned_data[:scm_revision] %>
|
14
|
-
<b>Revision:</b> <%= @cleaned_data[:scm_revision] %><br />
|
15
|
-
<% end %>
|
16
|
-
</body>
|
17
|
-
</html>
|
@@ -1,82 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
-
<head>
|
5
|
-
<title>Exception Email</title>
|
6
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
|
10
|
-
<% if @cleaned_data[:first_seen_at] %>
|
11
|
-
<p> This exception occurred <%= @cleaned_data[:occurrences] %> times since <%= @cleaned_data[:first_seen_at] %>.</p>
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<b>Error # </b><%= @cleaned_data[:timestamp] -%><br />
|
15
|
-
|
16
|
-
<b>URL:</b><br />
|
17
|
-
<% if (request = @cleaned_data[:request]) %>
|
18
|
-
<%= request[:url] || '<i>no URL in request data</i>'.html_safe %> <br />
|
19
|
-
Referred from: <%= (@cleaned_data[:environment]['HTTP_REFERER'] || '<i>no referrer</i>').html_safe %>
|
20
|
-
<% else %>
|
21
|
-
<i>no URL accessed</i>
|
22
|
-
<% end %>
|
23
|
-
<br />
|
24
|
-
<br />
|
25
|
-
|
26
|
-
<b>User summary:</b><br />
|
27
|
-
<% if (user_details = @cleaned_data[:user_details]) && ( user_details[:user] || user_details[:organization] ) %>
|
28
|
-
User: <%= h user_details[:user] %> (<%= h user_details[:username] %>)<br />
|
29
|
-
Organization: <%= user_details[:organization] %> <br />
|
30
|
-
<%= "Network: #{h user_details[:organization].network if user_details[:organization]}" if !user_details[:organization].is_a?(Network) %>
|
31
|
-
|
32
|
-
<% if @cleaned_data[:user_details][:impersonated_organization] %>
|
33
|
-
<br />
|
34
|
-
<b>Impersonating:</b><br />
|
35
|
-
Organization: <%= h @cleaned_data[:user_details][:impersonated_organization] %>
|
36
|
-
<% end %>
|
37
|
-
<% else %>
|
38
|
-
<i>No user logged in.</i>
|
39
|
-
<% end %>
|
40
|
-
|
41
|
-
<br />
|
42
|
-
<br />
|
43
|
-
<hr />
|
44
|
-
|
45
|
-
<h3>Exception:</h3>
|
46
|
-
<span id="error">
|
47
|
-
<%= h(@cleaned_data[:error]).gsub("\n","<br/>\n").gsub(/ {2,}/) { |spaces| ' '*spaces.size }.html_safe %>
|
48
|
-
</span>
|
49
|
-
|
50
|
-
<br />
|
51
|
-
<br />
|
52
|
-
|
53
|
-
<h3>Where:</h3>
|
54
|
-
<%= "#{ h location[:controller]}##{ h location[:action]}<br />".html_safe if (location = @cleaned_data[:location]) && location[:controller] -%>
|
55
|
-
<%= "#{ h location[:file]}, line #{ h location[:line]}<br />".html_safe if (location = @cleaned_data[:location]) && location[:file] -%>
|
56
|
-
|
57
|
-
<br />
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
<% for section in ExceptionHandling::ExceptionInfo::SECTIONS %>
|
62
|
-
<% section_value = @cleaned_data[section] %>
|
63
|
-
<% if section_value %>
|
64
|
-
<h3><%= section.to_s.capitalize -%>:</h3>
|
65
|
-
<pre id="<%= section.to_s.capitalize -%>" style="font-size: 12px; font-family: 'Courier New',Arial,sans-serif">
|
66
|
-
<%= case section_value
|
67
|
-
when Hash
|
68
|
-
section_value[:to_s]
|
69
|
-
when Array
|
70
|
-
section_value.join( "\n" )
|
71
|
-
when NilClass # omitted
|
72
|
-
else
|
73
|
-
raise "Unexpected value #{section_value.inspect} for section #{section}"
|
74
|
-
end
|
75
|
-
-%>
|
76
|
-
</pre>
|
77
|
-
<% end %>
|
78
|
-
|
79
|
-
<% end %>
|
80
|
-
|
81
|
-
</body>
|
82
|
-
</html>
|