exception_handling 1.0.3 → 1.0.4
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/Gemfile.lock +1 -1
- data/config/exception_filters.yml +5 -0
- data/lib/exception_handling/exception_catalog.rb +40 -0
- data/lib/exception_handling/exception_description.rb +58 -0
- data/lib/exception_handling/version.rb +1 -1
- data/lib/exception_handling.rb +13 -92
- data/test/unit/exception_handling/exception_catalog_test.rb +65 -0
- data/test/unit/exception_handling/exception_description_test.rb +71 -0
- data/test/unit/exception_handling_test.rb +25 -40
- data/views/exception_handling/mailer/exception_notification.html.erb +8 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07258fd3838c1f4ad88afcc407b5a48c515cc1bb
|
4
|
+
data.tar.gz: 6bc4a796d301b5739a71b6436a9a3c348f03f2f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 866f948f04a3ac4c2abf81d221c148a6c236692242dbc318743344dc4f8bc5fb14b39ece122895438ba4c7e48305baef130a489c1b5d712399822b9ff5bad448
|
7
|
+
data.tar.gz: 82e94f9f3eb8030a852a93f341cc7b7694070267edc3773fa74aa3e7e3ac66fbe145a5be242816b20202912016836ebfef6898ea31433b02295920c6e2c35f90
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
module ExceptionHandling
|
2
|
+
class ExceptionCatalog
|
3
|
+
|
4
|
+
def initialize(filter_path)
|
5
|
+
@filter_path = filter_path
|
6
|
+
@filters = { }
|
7
|
+
@filters_last_modified_time = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def find(exception_data)
|
11
|
+
refresh_filters
|
12
|
+
@filters.values.find { |filter| filter.match?(exception_data) }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def refresh_filters
|
18
|
+
mtime = last_modified_time
|
19
|
+
if @filters_last_modified_time.nil? || mtime != @filters_last_modified_time
|
20
|
+
ExceptionHandling.logger.info("Reloading filter list from: #{@filter_path}. Last loaded time: #{@filters_last_modified_time}. Last modified time: #{mtime}")
|
21
|
+
load_file
|
22
|
+
end
|
23
|
+
|
24
|
+
rescue => ex # any exceptions
|
25
|
+
ExceptionHandling::log_error(ex, "ExceptionRegexes::refresh_filters: #{@filter_path}", nil, true)
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_file
|
29
|
+
@filters_last_modified_time = last_modified_time # make race condition fall on the side of reloading unnecessarily next time rather than missing a set of changes
|
30
|
+
|
31
|
+
filters = YAML::load_file(@filter_path)
|
32
|
+
filter_hash_values = filters.map { |filter_name, regexes| [filter_name.to_sym, ExceptionDescription.new(filter_name.to_sym, regexes.symbolize_keys)] }
|
33
|
+
@filters = Hash[ filter_hash_values ]
|
34
|
+
end
|
35
|
+
|
36
|
+
def last_modified_time
|
37
|
+
File.mtime(@filter_path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ExceptionHandling
|
2
|
+
class ExceptionDescription
|
3
|
+
MATCH_SECTIONS = [:error, :request, :session, :environment, :backtrace, :event_response]
|
4
|
+
|
5
|
+
CONFIGURATION_SECTIONS = {
|
6
|
+
send_email: false, # should email be sent?
|
7
|
+
send_metric: true, # should the metric be sent.
|
8
|
+
metric_name: nil, # Will be derived from section name if not passed
|
9
|
+
notes: nil # Will be included in exception email if set, used to keep notes and relevant links
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :filter_name, :send_email, :send_metric, :metric_name, :notes
|
13
|
+
|
14
|
+
def initialize(filter_name, configuration)
|
15
|
+
@filter_name = filter_name
|
16
|
+
|
17
|
+
invalid_sections = configuration.except(*(CONFIGURATION_SECTIONS.keys + MATCH_SECTIONS))
|
18
|
+
invalid_sections.empty? or raise ArgumentError, "Unknown section: #{invalid_sections.keys.join(",")}"
|
19
|
+
|
20
|
+
@configuration = CONFIGURATION_SECTIONS.merge(configuration)
|
21
|
+
@send_email = @configuration[:send_email]
|
22
|
+
@send_metric = @configuration[:send_metric]
|
23
|
+
@metric_name = (@configuration[:metric_name] || @filter_name ).to_s.gsub(" ","_")
|
24
|
+
@notes = @configuration[:notes]
|
25
|
+
|
26
|
+
regex_config = @configuration.reject { |k,v| k.in?(CONFIGURATION_SECTIONS.keys) || v.blank? }
|
27
|
+
|
28
|
+
@regexes = Hash[regex_config.map { |section, regex| [section, Regexp.new(regex, 'i') ] }]
|
29
|
+
|
30
|
+
!@regexes.empty? or raise ArgumentError, "Filter #{filter_name} has all blank regexes: #{configuration.inspect}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def exception_data
|
34
|
+
{
|
35
|
+
"send_metric" => send_metric,
|
36
|
+
"metric_name" => metric_name,
|
37
|
+
"notes" => notes
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def match?(exception_data)
|
42
|
+
@regexes.all? do |section, regex|
|
43
|
+
case target = exception_data[section.to_s] || exception_data[section]
|
44
|
+
when String
|
45
|
+
regex =~ target
|
46
|
+
when Array
|
47
|
+
target.any? { |row| row =~ regex }
|
48
|
+
when Hash
|
49
|
+
target[:to_s] =~ regex
|
50
|
+
when NilClass
|
51
|
+
false
|
52
|
+
else
|
53
|
+
raise "Unexpected class #{exception_data[section].class.name}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/exception_handling.rb
CHANGED
@@ -7,6 +7,8 @@ require 'invoca/utils'
|
|
7
7
|
require "exception_handling/mailer"
|
8
8
|
require "exception_handling/methods"
|
9
9
|
require "exception_handling/log_stub_error"
|
10
|
+
require "exception_handling/exception_description"
|
11
|
+
require "exception_handling/exception_catalog"
|
10
12
|
|
11
13
|
_ = ActiveSupport::HashWithIndifferentAccess
|
12
14
|
|
@@ -351,22 +353,18 @@ EOF
|
|
351
353
|
|
352
354
|
SECTIONS.each { |section| add_to_s( data[section] ) if data[section].is_a? Hash }
|
353
355
|
|
354
|
-
|
355
|
-
|
356
|
-
end
|
357
|
-
|
358
|
-
if summarize_exception( data ) == :Summarized
|
359
|
-
return
|
360
|
-
end
|
356
|
+
exception_description = exception_catalog.find( data )
|
357
|
+
merged_data = exception_description ? ActiveSupport::HashWithIndifferentAccess.new(exception_description.exception_data.merge(data)) : data
|
361
358
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
359
|
+
if exception_description && !exception_description.send_email
|
360
|
+
ExceptionHandling.logger.warn( "Filtered exception using '#{exception_description.filter_name}'; not sending email to notify" )
|
361
|
+
else
|
362
|
+
if summarize_exception( merged_data ) != :Summarized
|
363
|
+
deliver(ExceptionHandling::Mailer.exception_notification(merged_data))
|
364
|
+
end
|
366
365
|
end
|
367
366
|
|
368
|
-
execute_custom_log_error_callback(
|
369
|
-
|
367
|
+
execute_custom_log_error_callback(merged_data, exc)
|
370
368
|
nil
|
371
369
|
end
|
372
370
|
|
@@ -470,8 +468,8 @@ EOF
|
|
470
468
|
end.compact ]
|
471
469
|
end
|
472
470
|
|
473
|
-
def
|
474
|
-
@
|
471
|
+
def exception_catalog
|
472
|
+
@exception_catalog ||= ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
|
475
473
|
end
|
476
474
|
|
477
475
|
def clean_backtrace(exception)
|
@@ -594,81 +592,4 @@ EOF
|
|
594
592
|
result
|
595
593
|
end
|
596
594
|
end
|
597
|
-
|
598
|
-
class ExceptionFilters
|
599
|
-
class Filter
|
600
|
-
def initialize filter_name, regexes
|
601
|
-
@regexes = Hash[ regexes.map do |section, regex|
|
602
|
-
section = section.to_sym
|
603
|
-
raise "Unknown section: #{section}" unless section == :error || section.in?( ExceptionHandling::SECTIONS )
|
604
|
-
[section, (Regexp.new(regex, 'i') unless regex.blank?)]
|
605
|
-
end ]
|
606
|
-
|
607
|
-
raise "Filter #{filter_name} has all blank regexes: #{regexes.inspect}" if @regexes.all? { |section, regex| regex.nil? }
|
608
|
-
end
|
609
|
-
|
610
|
-
def match?(exception_data)
|
611
|
-
@regexes.all? do |section, regex|
|
612
|
-
regex.nil? ||
|
613
|
-
case exception_data[section.to_s]
|
614
|
-
when String
|
615
|
-
regex =~ exception_data[section]
|
616
|
-
when Array
|
617
|
-
exception_data[section].any? { |row| row =~ regex }
|
618
|
-
when Hash
|
619
|
-
exception_data[section] && exception_data[section][:to_s] =~ regex
|
620
|
-
when NilClass
|
621
|
-
false
|
622
|
-
else
|
623
|
-
raise "Unexpected class #{exception_data[section].class.name}"
|
624
|
-
end
|
625
|
-
end
|
626
|
-
end
|
627
|
-
end
|
628
|
-
|
629
|
-
def initialize( filter_path )
|
630
|
-
@filter_path = filter_path
|
631
|
-
@filters = { }
|
632
|
-
@filters_last_modified_time = nil
|
633
|
-
end
|
634
|
-
|
635
|
-
def filtered?( exception_data )
|
636
|
-
refresh_filters
|
637
|
-
|
638
|
-
@filters.any? do |name, filter|
|
639
|
-
if ( match = filter.match?( exception_data ) )
|
640
|
-
ExceptionHandling.logger.warn( "Filtered exception using '#{name}'; not sending email to notify" )
|
641
|
-
end
|
642
|
-
match
|
643
|
-
end
|
644
|
-
end
|
645
|
-
|
646
|
-
private
|
647
|
-
|
648
|
-
def refresh_filters
|
649
|
-
mtime = last_modified_time
|
650
|
-
if @filters_last_modified_time.nil? || mtime != @filters_last_modified_time
|
651
|
-
ExceptionHandling.logger.info( "Reloading filter list from: #{@filter_path}. Last loaded time: #{@filters_last_modified_time}. Last modified time: #{mtime}" )
|
652
|
-
@filters_last_modified_time = mtime # make race condition fall on the side of reloading unnecessarily next time rather than missing a set of changes
|
653
|
-
|
654
|
-
@filters = load_file
|
655
|
-
end
|
656
|
-
|
657
|
-
rescue => ex # any exceptions
|
658
|
-
ExceptionHandling::log_error( ex, "ExceptionRegexes::refresh_filters: #{@filter_path}", nil, true)
|
659
|
-
end
|
660
|
-
|
661
|
-
def load_file
|
662
|
-
# store all strings from YAML file into regex's on initial load, instead of converting to regex on every exception that is logged
|
663
|
-
filters = YAML::load_file( @filter_path )
|
664
|
-
Hash[ filters.map do |filter_name, regexes|
|
665
|
-
[filter_name, Filter.new( filter_name, regexes )]
|
666
|
-
end ]
|
667
|
-
end
|
668
|
-
|
669
|
-
def last_modified_time
|
670
|
-
File.mtime( @filter_path )
|
671
|
-
end
|
672
|
-
|
673
|
-
end
|
674
595
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module ExceptionHandling
|
4
|
+
class ExceptionCatalogTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
context "With stubbed yaml content" do
|
7
|
+
setup do
|
8
|
+
filter_list = { :exception1 => { error: "my error message" },
|
9
|
+
:exception2 => { error: "some other message", session: "misc data" } }
|
10
|
+
stub(YAML).load_file { filter_list }
|
11
|
+
|
12
|
+
# bump modified time up to get the above filter loaded
|
13
|
+
stub(File).mtime { incrementing_mtime }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with loaded data" do
|
17
|
+
setup do
|
18
|
+
stub(File).mtime { incrementing_mtime }
|
19
|
+
@exception_catalog = ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
|
20
|
+
@exception_catalog.send :load_file
|
21
|
+
end
|
22
|
+
|
23
|
+
should "have loaded filters" do
|
24
|
+
assert_equal 2, @exception_catalog.instance_eval("@filters").size
|
25
|
+
end
|
26
|
+
|
27
|
+
should "find messages in the catalog" do
|
28
|
+
assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
|
29
|
+
end
|
30
|
+
|
31
|
+
should "find matching data" do
|
32
|
+
exception_description = @exception_catalog.find(error: "this is my error message, which should match something")
|
33
|
+
assert exception_description
|
34
|
+
assert_equal :exception1, exception_description.filter_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with live yaml content" do
|
41
|
+
setup do
|
42
|
+
@filename = File.expand_path('../../../../config/exception_filters.yml', __FILE__)
|
43
|
+
@exception_catalog = ExceptionCatalog.new( @filename )
|
44
|
+
assert_nothing_raised "Loading the exception filter should not raise" do
|
45
|
+
@exception_catalog.send :load_file
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
should "load the filter data" do
|
50
|
+
assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
|
51
|
+
assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def incrementing_mtime
|
60
|
+
@mtime ||= Time.now
|
61
|
+
@mtime += 1.day
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module ExceptionHandling
|
4
|
+
class ExceptionDescriptionTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
context "Filter" do
|
7
|
+
|
8
|
+
should "allow direct matching of strings" do
|
9
|
+
@f = ExceptionDescription.new(:filter1, :error => "my error message" )
|
10
|
+
assert @f.match?( 'error' => "my error message")
|
11
|
+
end
|
12
|
+
|
13
|
+
should "allow direct matching of strings on with symbol keys" do
|
14
|
+
@f = ExceptionDescription.new(:filter1, :error => "my error message" )
|
15
|
+
assert @f.match?( :error => "my error message")
|
16
|
+
end
|
17
|
+
|
18
|
+
should "complain when no regexps have a value" do
|
19
|
+
assert_raise(ArgumentError, "has all blank regexe") { ExceptionDescription.new(:filter1, error: nil) }
|
20
|
+
end
|
21
|
+
|
22
|
+
should "report when an invalid key is passed" do
|
23
|
+
assert_raise(ArgumentError, "Unknown section: not_a_parameter") { ExceptionDescription.new(:filter1, error: "my error message", not_a_parameter: false) }
|
24
|
+
end
|
25
|
+
|
26
|
+
should "allow send email to be specified" do
|
27
|
+
assert !ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).send_email
|
28
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_email
|
29
|
+
assert !ExceptionDescription.new(:filter1, error: "my error message" ).send_email
|
30
|
+
end
|
31
|
+
|
32
|
+
should "allow send_metric to be configured" do
|
33
|
+
assert !ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).send_metric
|
34
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_metric
|
35
|
+
assert ExceptionDescription.new(:filter1, error: "my error message" ).send_metric
|
36
|
+
end
|
37
|
+
|
38
|
+
should "provide metric name" do
|
39
|
+
assert_equal "filter1", ExceptionDescription.new(:filter1, error: "my error message" ).metric_name
|
40
|
+
assert_equal "some_other_metric_name", ExceptionDescription.new(:filter1, error: "my error message", metric_name: :some_other_metric_name ).metric_name
|
41
|
+
end
|
42
|
+
|
43
|
+
should "replace spaces in metric name" do
|
44
|
+
@f = ExceptionDescription.new(:"filter has spaces", :error => "my error message" )
|
45
|
+
assert_equal "filter_has_spaces", @f.metric_name
|
46
|
+
end
|
47
|
+
|
48
|
+
should "allow notes to be recorded" do
|
49
|
+
assert_equal nil, ExceptionDescription.new(:filter1, error: "my error message" ).notes
|
50
|
+
assert_equal "a long string", ExceptionDescription.new(:filter1, error: "my error message", notes: "a long string" ).notes
|
51
|
+
end
|
52
|
+
|
53
|
+
should "not consider config options in the filter set" do
|
54
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).match?( :error => "my error message")
|
55
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).match?( :error => "my error message")
|
56
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", metric_name: "false" ).match?( :error => "my error message")
|
57
|
+
assert ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" ).match?( :error => "my error message")
|
58
|
+
end
|
59
|
+
|
60
|
+
should "provide exception details" do
|
61
|
+
exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" )
|
62
|
+
|
63
|
+
expected = {"send_metric" => true, "metric_name" => "filter1", "notes" => "hey"}
|
64
|
+
|
65
|
+
assert_equal expected, exception_description.exception_data
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -48,7 +48,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
48
48
|
end
|
49
49
|
|
50
50
|
context "configuration" do
|
51
|
-
def
|
51
|
+
def append_organization_info_config(data)
|
52
52
|
begin
|
53
53
|
data[:user_details] = {}
|
54
54
|
data[:user_details][:username] = "CaryP"
|
@@ -58,7 +58,8 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
61
|
+
def log_error_callback_config(data, ex)
|
62
|
+
@callback_data = data
|
62
63
|
@fail_count += 1
|
63
64
|
end
|
64
65
|
|
@@ -71,17 +72,23 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
71
72
|
end
|
72
73
|
|
73
74
|
should "support a custom_data_hook" do
|
74
|
-
ExceptionHandling.custom_data_hook = method(:
|
75
|
+
ExceptionHandling.custom_data_hook = method(:append_organization_info_config)
|
75
76
|
ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
|
76
77
|
assert_match(/Invoca Engineering Dept./, ActionMailer::Base.deliveries[-1].body.to_s)
|
77
78
|
ExceptionHandling.custom_data_hook = nil
|
78
79
|
end
|
79
80
|
|
80
|
-
should "support a log_error hook" do
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
should "support a log_error hook and pass exception data to it" do
|
82
|
+
begin
|
83
|
+
ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
|
84
|
+
ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
|
85
|
+
assert_equal 1, @fail_count
|
86
|
+
ensure
|
87
|
+
ExceptionHandling.post_log_error_hook = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
assert_equal "this is used by a test", @callback_data["notes"]
|
91
|
+
assert_match(/this is used by a test/, ActionMailer::Base.deliveries[-1].body.to_s)
|
85
92
|
end
|
86
93
|
|
87
94
|
should "support rescue exceptions from a log_error hook" do
|
@@ -90,6 +97,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
90
97
|
assert_equal 0, @fail_count
|
91
98
|
ExceptionHandling.post_log_error_hook = nil
|
92
99
|
end
|
100
|
+
|
93
101
|
end
|
94
102
|
|
95
103
|
context "Exception Handling" do
|
@@ -98,18 +106,6 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
98
106
|
ExceptionHandling.send(:clear_exception_summary)
|
99
107
|
end
|
100
108
|
|
101
|
-
context "exception filter parsing and loading" do
|
102
|
-
should "happen without an error" do
|
103
|
-
stub(File).mtime { incrementing_mtime }
|
104
|
-
exception_filters = ExceptionHandling.send( :exception_filters )
|
105
|
-
assert( exception_filters.is_a?( ExceptionHandling::ExceptionFilters ) )
|
106
|
-
assert_nothing_raised "Loading the exception filter should not raise" do
|
107
|
-
exception_filters.send :load_file
|
108
|
-
end
|
109
|
-
assert !exception_filters.filtered?( "Scott says unlikely to ever match" )
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
109
|
context "ExceptionHandling.ensure_safe" do
|
114
110
|
should "log an exception if an exception is raised." do
|
115
111
|
mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/)
|
@@ -232,6 +228,11 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
232
228
|
Time.now_override = Time.parse( '1986-5-21 4:17 am UTC' )
|
233
229
|
end
|
234
230
|
|
231
|
+
def log_error_callback(data, ex)
|
232
|
+
@fail_count += 1
|
233
|
+
end
|
234
|
+
|
235
|
+
|
235
236
|
should "include the timestamp when the exception is logged" do
|
236
237
|
mock(ExceptionHandling.logger).fatal(/\(Error:517033020\) ArgumentError mooo \(blah\):\n.*exception_handling_test\.rb/)
|
237
238
|
b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError.new("blah") }
|
@@ -252,12 +253,15 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
252
253
|
assert_match(/Exception 2/, ActionMailer::Base.deliveries[-1].subject)
|
253
254
|
end
|
254
255
|
|
255
|
-
should "only send 5 of a repeated error" do
|
256
|
+
should "only send 5 of a repeated error, but call post hook for every exception" do
|
257
|
+
@fail_count = 0
|
258
|
+
ExceptionHandling.post_log_error_hook = method(:log_error_callback)
|
256
259
|
assert_emails 5 do
|
257
260
|
10.times do
|
258
261
|
ExceptionHandling.log_error(exception_1)
|
259
262
|
end
|
260
263
|
end
|
264
|
+
assert_equal 10, @fail_count
|
261
265
|
end
|
262
266
|
|
263
267
|
should "only send 5 of a repeated error but don't send summary if 6th is different" do
|
@@ -671,25 +675,6 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
671
675
|
end
|
672
676
|
end
|
673
677
|
|
674
|
-
context "Errplane" do
|
675
|
-
module ErrplaneStub
|
676
|
-
end
|
677
|
-
|
678
|
-
setup do
|
679
|
-
set_test_const('Errplane', ErrplaneStub)
|
680
|
-
end
|
681
|
-
|
682
|
-
should "forward exceptions" do
|
683
|
-
mock(Errplane).transmit(exception_1, anything)
|
684
|
-
ExceptionHandling.log_error(exception_1, "context")
|
685
|
-
end
|
686
|
-
|
687
|
-
should "not forward warnings" do
|
688
|
-
stub(Errplane).transmit.times(0)
|
689
|
-
ExceptionHandling.log_warning("warning message")
|
690
|
-
end
|
691
|
-
end
|
692
|
-
|
693
678
|
private
|
694
679
|
|
695
680
|
def incrementing_mtime
|
@@ -27,6 +27,14 @@
|
|
27
27
|
<br />
|
28
28
|
<br />
|
29
29
|
|
30
|
+
<% if @cleaned_data[:notes] %>
|
31
|
+
<b>Exception Notes:</b> (from config/exception.yml)<br />
|
32
|
+
<%= @cleaned_data[:notes].gsub("\n","<br/>\n").gsub(/ {2,}/) { |spaces| ' '*spaces.size }.html_safe %>
|
33
|
+
<br />
|
34
|
+
<br />
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
|
30
38
|
<b>User summary:</b><br />
|
31
39
|
<% if (user_details = @cleaned_data[:user_details]) && ( user_details[:user] || user_details[:organization] ) %>
|
32
40
|
User: <%= user_details[:user] %> (<%= user_details[:username] %>)<br />
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exception_handling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Colin Kelley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eventmachine
|
@@ -167,12 +167,16 @@ files:
|
|
167
167
|
- config/exception_filters.yml
|
168
168
|
- exception_handling.gemspec
|
169
169
|
- lib/exception_handling.rb
|
170
|
+
- lib/exception_handling/exception_catalog.rb
|
171
|
+
- lib/exception_handling/exception_description.rb
|
170
172
|
- lib/exception_handling/log_stub_error.rb
|
171
173
|
- lib/exception_handling/mailer.rb
|
172
174
|
- lib/exception_handling/methods.rb
|
173
175
|
- lib/exception_handling/testing.rb
|
174
176
|
- lib/exception_handling/version.rb
|
175
177
|
- test/test_helper.rb
|
178
|
+
- test/unit/exception_handling/exception_catalog_test.rb
|
179
|
+
- test/unit/exception_handling/exception_description_test.rb
|
176
180
|
- test/unit/exception_handling/log_error_stub_test.rb
|
177
181
|
- test/unit/exception_handling/mailer_test.rb
|
178
182
|
- test/unit/exception_handling/methods_test.rb
|
@@ -206,6 +210,8 @@ summary: Invoca's exception handling logger/emailer layer, based on exception_no
|
|
206
210
|
Works with Rails or EventMachine or EventMachine+Synchrony.
|
207
211
|
test_files:
|
208
212
|
- test/test_helper.rb
|
213
|
+
- test/unit/exception_handling/exception_catalog_test.rb
|
214
|
+
- test/unit/exception_handling/exception_description_test.rb
|
209
215
|
- test/unit/exception_handling/log_error_stub_test.rb
|
210
216
|
- test/unit/exception_handling/mailer_test.rb
|
211
217
|
- test/unit/exception_handling/methods_test.rb
|