eh 0.0.1 → 0.0.3

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.
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Eh
2
2
 
3
- The Error handler gem provids the following major functional support for error handling:
3
+ The Error handler gem provides the following major functional support for error handling,
4
+ based on the ideas expressed in the Exceptional Ruby book by Avdi Grimm
4
5
 
5
- o Wrapping of code blocks in exception handling logic, supporting retry, logging and exception consumption
6
+ o Wrapping of code blocks in exception handling logic, supporting retry, logging and exception consumption, as well as a list of handlers that can be injected
6
7
  o Provision of fault tolerant logging that logs to configured logger(s), or to stderr should loggers be unavailable
7
8
  o Capability to handle unhandled exceptions, log them, email them and either raise them again or convert them to system exit codes (listing of standard linux exit codes provided as constants)
8
9
 
@@ -10,10 +11,11 @@ The Error Handler gem allows the wrapping of arbitrary blocks of code in excepti
10
11
 
11
12
  o The block can be retried 'threshold' times, with a delay of 'delay' seconds in-between retries (EH::retry and EH::retry!)
12
13
  o The exception can be logged to a single logger, or an array of loggers
13
- o The excepion can be re-raised (suppressed during retry, but logged, raised again after retry failure)
14
+ o The exception can be re-raised (suppressed during retry, but logged, raised again after retry failure)
14
15
  o The same functionality is available, with retry disabled (EH::run and EH::run!)
15
16
  o The list of Linux system exit codes is also provided as EH::EX_<exit>
16
17
  o Unhandled exceptions can be logged and emailed in main() using EH::report_unhandled()
18
+ o A list of handlers can be injected to do custom handling, such as email, roll-back, etc.
17
19
 
18
20
  This gem is sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
19
21
 
@@ -33,14 +35,20 @@ Or install it yourself as:
33
35
 
34
36
  ## Usage
35
37
 
38
+ require 'rubygems'
39
+ require 'eh/eh'
40
+
36
41
  -- Run code block with retry, logging and exception re-raise, specifying logger, number of
37
- times to retry, retry delay, and block arguments
42
+ times to retry, retry delay, and block arguments. Also call handle(exception, message) on
43
+ the list of handlers provided
38
44
  def load_configuration(configuration_path, logger = nil)
39
45
  EH::retry!(:logger => logger,
40
46
  :message => "Could not parse YAML configuration",
41
47
  :args => [configuration_path],
42
48
  :threshold => 5,
43
- :delay => 0.5) do
49
+ :delay => 0.5,
50
+ :exception_filter => [RuntimeError, IOError],
51
+ :handlers => [MyEmailHandler.new, MyOtherHandler.new]) do
44
52
  YAML.load(File.open(configuration_path))
45
53
  end
46
54
  end
@@ -68,7 +76,7 @@ Any combination of the following options are allowed, both with both flavours of
68
76
  :args - code block arguments
69
77
  :threshold - the number of execution attempts
70
78
  :delay - the number of seconds to delay between retries
71
-
79
+ :handlers - an array of handlers that implement handle(exception, message)
72
80
 
73
81
  Function descriptions:
74
82
 
data/eh.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'eh/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "eh"
8
8
  spec.version = ErrorHandler::VERSION
9
- spec.authors = ["Ernst ban Graan"]
10
- spec.email = ["ernst.van.graan@hetzner.co.za"]
9
+ spec.authors = ["Ernst van Graan, Wynand van Dyk"]
10
+ spec.email = ["ernst.van.graan@hetzner.co.za", "wynand.van.dyk@hetzner.co.za"]
11
11
  spec.description = %q{Error handler gem that allows wrapping of code blocks with support for block retry, logging, exception filtering and re-raise}
12
12
  spec.summary = %q{Error handler gem that allows wrapping of code blocks with support for block retry, logging, exception filtering and re-raise}
13
13
  spec.homepage = ""
@@ -47,7 +47,9 @@ module ErrorHandler
47
47
  rescue => e
48
48
  raise e if opts.nil? == false and opts[:exception_filter] and not opts[:exception_filter].include? e.class
49
49
 
50
- EH::log(opts[:logger], "#{opts[:message]}: #{e.message}", EH::log_level(opts)) if opts.nil? == false and not opts[:logger].nil? and not opts[:message].nil?
50
+ msg = "#{opts[:message]}: #{e.message}"
51
+ EH::log(opts[:logger], msg, EH::log_level(opts)) if opts.nil? == false and not opts[:logger].nil? and not opts[:message].nil?
52
+ EH::handle(opts[:handlers], e, msg) if not opts[:handlers].nil?
51
53
  raise e
52
54
  end
53
55
 
@@ -57,9 +59,11 @@ module ErrorHandler
57
59
  EH::retry_with_raise(opts, block)
58
60
  return true
59
61
  rescue => e
62
+ msg = "#{opts[:message]}: #{e.message}"
60
63
  if not opts[:logger].nil?
61
- EH::log(opts[:logger], "#{opts[:message]}: #{e.message}", EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
64
+ EH::log(opts[:logger], msg, EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
62
65
  end
66
+ EH::handle(opts[:handlers], e, msg) if not opts[:handlers].nil?
63
67
  return false
64
68
  end
65
69
  end
@@ -69,9 +73,11 @@ module ErrorHandler
69
73
  block.call(EH::construct_args(opts))
70
74
 
71
75
  rescue => e
76
+ msg = "#{opts[:message]}: #{e.message}"
72
77
  if not opts[:logger].nil?
73
- EH::log(opts[:logger], "#{opts[:message]}: #{e.message}", EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
78
+ EH::log(opts[:logger], msg, EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
74
79
  end
80
+ EH::handle(opts[:handlers], e, msg) if not opts[:handlers].nil?
75
81
 
76
82
  raise e if opts.nil? == false and opts[:exception_filter] and not opts[:exception_filter].include? e.class
77
83
  raise e
@@ -82,9 +88,11 @@ module ErrorHandler
82
88
  block.call(EH::construct_args(opts))
83
89
 
84
90
  rescue => e
91
+ msg = "#{opts[:message]}: #{e.message}"
85
92
  if not opts[:logger].nil?
86
- EH::log(opts[:logger], "#{opts[:message]}: #{e.message}", EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
93
+ EH::log(opts[:logger], msg, EH::log_level(opts)) if opts[:exception_filter].nil? or opts[:exception_filter].include? e.class
87
94
  end
95
+ EH::handle(opts[:handlers], e, msg) if not opts[:handlers].nil?
88
96
  end
89
97
 
90
98
  def self.log(facilities, msg, msg_type)
@@ -95,8 +103,23 @@ module ErrorHandler
95
103
  end
96
104
  end
97
105
 
106
+ def self.generate_log_id
107
+ ms = Time.now
108
+ end
109
+
98
110
  private
99
111
 
112
+ def self.handle(handlers, e, msg)
113
+ return if handlers.nil?
114
+ if handlers.is_a? Array
115
+ handlers.each do |handler|
116
+ handler.handle(e, msg) if not handler.nil?
117
+ end
118
+ else
119
+ handlers.handle(e, msg)
120
+ end
121
+ end
122
+
100
123
  def self.construct_args(opts)
101
124
  return nil if opts.nil?
102
125
  return nil if opts[:args].nil?
@@ -119,30 +142,6 @@ module ErrorHandler
119
142
  end
120
143
  end
121
144
 
122
- # Coming soon...
123
- # def send_email(to, message, opts={})
124
- # require 'net/smtp'
125
- #
126
- # opts[:server] ||= Socket.gethostbyname(Socket.gethostname).first
127
- # me = "database-agent@#{opts[:server]}"
128
- # opts[:from] ||= me
129
- # opts[:from_alias] ||= me
130
- # opts[:subject] ||= "Uncaught exception"
131
- # opts[:body] ||= message
132
- #
133
- # msg = <<END_OF_MESSAGE
134
- #From: #{opts[:from_alias]} <#{opts[:from]}>
135
- #To: <#{to}>
136
- #Subject: #{opts[:subject]}
137
- #
138
- # #{opts[:body]}
139
- #END_OF_MESSAGE
140
- #
141
- # Net::SMTP.start(opts[:server]) do |smtp|
142
- # smtp.send_message msg, opts[:from], to
143
- # end
144
- # end
145
-
146
145
  def self.log_single_logger(logger, msg, msg_type)
147
146
  if logger.nil?
148
147
  warn msg_type + ': ' + msg
@@ -168,4 +167,4 @@ module ErrorHandler
168
167
  end
169
168
  end
170
169
 
171
- EH = ErrorHandler::EH
170
+ EH = ErrorHandler::EH
@@ -1,3 +1,3 @@
1
1
  module ErrorHandler
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,10 +1,12 @@
1
1
  require "spec_helper"
2
2
  require "eh/eh"
3
3
  require "mock_logger"
4
+ require "mock_mailer"
4
5
 
5
6
  describe ErrorHandler do
6
7
  before :each do
7
8
  @logger = MockLogger.new
9
+ @mailer = MockMailer.new
8
10
  end
9
11
 
10
12
  context "When executing a block of code without retry" do
@@ -42,6 +44,30 @@ describe ErrorHandler do
42
44
  end
43
45
  end
44
46
 
47
+ it "should inform all handlers specified of the message and exception" do
48
+ @mailer.should_receive(:handle)
49
+ @handler2 = MockMailer.new
50
+ begin
51
+ EH::run(:handlers => [@mailer, @handler2], :message => "the message") do
52
+ raise RuntimeError
53
+ end
54
+ end
55
+
56
+ @handler2.e.class.should == RuntimeError
57
+ @handler2.msg.should == "the message: RuntimeError"
58
+ end
59
+
60
+ it "should inform a specified handler of the message and exception" do
61
+ begin
62
+ EH::run(:handlers => @mailer, :message => "the message") do
63
+ raise RuntimeError
64
+ end
65
+ end
66
+
67
+ @mailer.e.class.should == RuntimeError
68
+ @mailer.msg.should == "the message: RuntimeError"
69
+ end
70
+
45
71
  it "should log the message specified with the exception appended, if the exception is in :exception_filter, using the logger specified" do
46
72
  @logger.should_receive(:error).with("the message: RuntimeError")
47
73
  begin
@@ -105,6 +131,32 @@ describe ErrorHandler do
105
131
  end
106
132
  end
107
133
 
134
+ it "should inform all handlers specified of the message and exception" do
135
+ @mailer.should_receive(:handle)
136
+ @handler2 = MockMailer.new
137
+ begin
138
+ EH::run(:handlers => [@mailer, @handler2], :message => "the message") do
139
+ raise RuntimeError
140
+ end
141
+ rescue => e
142
+ end
143
+
144
+ @handler2.e.class.should == RuntimeError
145
+ @handler2.msg.should == "the message: RuntimeError"
146
+ end
147
+
148
+ it "should inform a specified handler of the message and exception" do
149
+ begin
150
+ EH::run(:handlers => @mailer, :message => "the message") do
151
+ raise RuntimeError
152
+ end
153
+ rescue => e
154
+ end
155
+
156
+ @mailer.e.class.should == RuntimeError
157
+ @mailer.msg.should == "the message: RuntimeError"
158
+ end
159
+
108
160
  it "should log the message specified with the exception appended, if the exception is in :exception_filter, using the logger specified" do
109
161
  @logger.should_receive(:error).with("the message: RuntimeError")
110
162
  begin
@@ -213,6 +265,30 @@ describe ErrorHandler do
213
265
  end
214
266
  end
215
267
 
268
+ it "should inform all handlers specified of the message and exception" do
269
+ @mailer.should_receive(:handle)
270
+ @handler2 = MockMailer.new
271
+ begin
272
+ EH::run(:handlers => [@mailer, @handler2], :message => "the message") do
273
+ raise RuntimeError
274
+ end
275
+ end
276
+
277
+ @handler2.e.class.should == RuntimeError
278
+ @handler2.msg.should == "the message: RuntimeError"
279
+ end
280
+
281
+ it "should inform a specified handler of the message and exception" do
282
+ begin
283
+ EH::run(:handlers => @mailer, :message => "the message") do
284
+ raise RuntimeError
285
+ end
286
+ end
287
+
288
+ @mailer.e.class.should == RuntimeError
289
+ @mailer.msg.should == "the message: RuntimeError"
290
+ end
291
+
216
292
  it "should log the message specified with the exception appended, if the exception is in :exception_filter, using the logger specified" do
217
293
  @logger.should_receive(:error).with("the message: RuntimeError")
218
294
  begin
@@ -300,6 +376,32 @@ describe ErrorHandler do
300
376
  end
301
377
  end
302
378
 
379
+ it "should inform all handlers specified of the message and exception" do
380
+ @mailer.should_receive(:handle)
381
+ @handler2 = MockMailer.new
382
+ begin
383
+ EH::run(:handlers => [@mailer, @handler2], :message => "the message") do
384
+ raise RuntimeError
385
+ end
386
+ rescue => e
387
+ end
388
+
389
+ @handler2.e.class.should == RuntimeError
390
+ @handler2.msg.should == "the message: RuntimeError"
391
+ end
392
+
393
+ it "should inform a specified handler of the message and exception" do
394
+ begin
395
+ EH::run(:handlers => @mailer, :message => "the message") do
396
+ raise RuntimeError
397
+ end
398
+ rescue => e
399
+ end
400
+
401
+ @mailer.e.class.should == RuntimeError
402
+ @mailer.msg.should == "the message: RuntimeError"
403
+ end
404
+
303
405
  it "should log the message specified with the exception appended, if the exception is in :exception_filter, using the logger specified" do
304
406
  @logger.should_receive(:error).with("the message: RuntimeError")
305
407
  begin
@@ -0,0 +1,9 @@
1
+ class MockMailer
2
+ attr_accessor :e
3
+ attr_accessor :msg
4
+
5
+ def handle(e, msg)
6
+ @e = e
7
+ @msg = msg
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ require 'rspec'
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib', 'eh'))
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ # Run specs in random order to surface order dependencies. If you find an
12
+ # order dependency and want to debug it, you can fix the order by providing
13
+ # the seed, which is printed after each run.
14
+ # --seed 1234
15
+ config.order = 'random'
16
+ end
metadata CHANGED
@@ -1,88 +1,90 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: eh
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
6
11
  platform: ruby
7
- authors:
8
- - Ernst ban Graan
12
+ authors:
13
+ - Ernst van Graan, Wynand van Dyk
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2013-03-06 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2013-03-07 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: bundler
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ~>
20
- - !ruby/object:Gem::Version
21
- version: '1.3'
22
- type: :development
23
22
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
- requirements:
25
+ requirements:
27
26
  - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '1.3'
30
- - !ruby/object:Gem::Dependency
31
- name: rake
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
27
+ - !ruby/object:Gem::Version
28
+ hash: 9
29
+ segments:
30
+ - 1
31
+ - 3
32
+ version: "1.3"
38
33
  type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
39
37
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: rspec
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
54
47
  type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
55
51
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: simplecov
64
- requirement: !ruby/object:Gem::Requirement
52
+ requirement: &id003 !ruby/object:Gem::Requirement
65
53
  none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
70
61
  type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: simplecov
71
65
  prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
66
+ requirement: &id004 !ruby/object:Gem::Requirement
73
67
  none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- description: Error handler gem that allows wrapping of code blocks with support for
79
- block retry, logging, exception filtering and re-raise
80
- email:
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ description: Error handler gem that allows wrapping of code blocks with support for block retry, logging, exception filtering and re-raise
78
+ email:
81
79
  - ernst.van.graan@hetzner.co.za
80
+ - wynand.van.dyk@hetzner.co.za
82
81
  executables: []
82
+
83
83
  extensions: []
84
+
84
85
  extra_rdoc_files: []
85
- files:
86
+
87
+ files:
86
88
  - .gitignore
87
89
  - Gemfile
88
90
  - LICENSE.txt
@@ -94,38 +96,43 @@ files:
94
96
  - lib/error_handler.rb
95
97
  - spec/eh_spec.rb
96
98
  - spec/mock_logger.rb
97
- homepage: ''
98
- licenses:
99
+ - spec/mock_mailer.rb
100
+ - spec/spec_helper.rb
101
+ homepage: ""
102
+ licenses:
99
103
  - MIT
100
104
  post_install_message:
101
105
  rdoc_options: []
102
- require_paths:
106
+
107
+ require_paths:
103
108
  - lib
104
- required_ruby_version: !ruby/object:Gem::Requirement
109
+ required_ruby_version: !ruby/object:Gem::Requirement
105
110
  none: false
106
- requirements:
107
- - - ! '>='
108
- - !ruby/object:Gem::Version
109
- version: '0'
110
- segments:
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
111
116
  - 0
112
- hash: 798203344795618863
113
- required_rubygems_version: !ruby/object:Gem::Requirement
117
+ version: "0"
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
119
  none: false
115
- requirements:
116
- - - ! '>='
117
- - !ruby/object:Gem::Version
118
- version: '0'
119
- segments:
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ hash: 3
124
+ segments:
120
125
  - 0
121
- hash: 798203344795618863
126
+ version: "0"
122
127
  requirements: []
128
+
123
129
  rubyforge_project:
124
130
  rubygems_version: 1.8.24
125
131
  signing_key:
126
132
  specification_version: 3
127
- summary: Error handler gem that allows wrapping of code blocks with support for block
128
- retry, logging, exception filtering and re-raise
129
- test_files:
133
+ summary: Error handler gem that allows wrapping of code blocks with support for block retry, logging, exception filtering and re-raise
134
+ test_files:
130
135
  - spec/eh_spec.rb
131
136
  - spec/mock_logger.rb
137
+ - spec/mock_mailer.rb
138
+ - spec/spec_helper.rb