eh 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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