babysitter 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,7 +7,7 @@ When provided with a Logger it will output statistics of progress to the logs.
7
7
 
8
8
  Add this line to your application's Gemfile:
9
9
 
10
- gem "babysitter"
10
+ gem "babysitter", git: 'git@github.com:lonelyplanet/babysitter.git'
11
11
 
12
12
  And then execute:
13
13
 
@@ -28,32 +28,13 @@ Or install it yourself as:
28
28
 
29
29
  The default logger does nothing, override if you want to see log output.
30
30
 
31
- ### Amazon Simple Notification Service Integration
32
-
33
- Babysitter can also make use of Amazons Simple Notification Service to provide notifications of when exceptions occur.
34
-
35
- Babysitter.configure do |c|
36
- c.enable_simple_notification_service(
37
- topic_arn: "my-topic-arn",
38
- credentials: -> {
39
- access_key_id: "YOUR_ACCESS_KEY_ID",
40
- secret_address_key: "YOUR_SECRET_ADDRESS_KEY",
41
- }
42
- )
43
- end
44
-
45
- The credentials should be supplied as a Proc so that they are only requested when they are required. This supports the use of temporary
46
- credentials with IAM and prevents any credentials fetched at configuration time having expired at some point later when an error occurs.
47
-
48
31
  ### Monitoring
49
32
 
50
33
  monitor = Babysitter.monitor("statsd.bucket.name")
51
- monitor.start("Workername: description") do |tracker|
34
+ monitor.start("Workername: description") do |progress|
52
35
  things_to_do.each do |work|
53
36
  do_some work
54
- tracker.error(:badness,'Something bad happened') if something_bad?
55
- tracker.warn(:suspicions,'Something supicious happenedd') if something_bad?
56
- tracker.inc("Workername: {{count}} tasks completed", 1, counting: :things_to_do) # report progress here
37
+ progress.inc("Workername: {{count}} tasks completed", 1, counting: :work_things) # report progress here
57
38
  end
58
39
  end
59
40
 
@@ -61,15 +42,10 @@ credentials with IAM and prevents any credentials fetched at configuration time
61
42
  This will send statistics to StatsD in the supplied bucket name and will generate logs like this:
62
43
 
63
44
 
64
- INFO -- : Start: statsd.bucket.name Matcher generating possible combinations
45
+ INFO -- : Start: update.combinations Matcher generating possible combinations
65
46
  INFO -- : Done: 100 combinations generated
66
47
  INFO -- : Rate: 20746.88796680498 combinations per second
67
- INFO -- : End: statsd.bucket.name
68
-
69
- Logging statistics will incremented for bucket names
70
-
71
- statsd.bucket.name.badness.errors
72
- statsd.bucket.name.suspicions.warnings
48
+ INFO -- : End: update.combinations
73
49
 
74
50
 
75
51
  Any exceptions that occur will be logged nicely. Exceptions will abort the process.
@@ -6,8 +6,8 @@ require 'babysitter/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "babysitter"
8
8
  gem.version = Babysitter::VERSION
9
- gem.authors = ["Nicolas Overloop", "Paul Grayson", "Andy Roberts", "Mike Wagg"]
10
- gem.email = ["noverloop@gmail.com", "paul.grayson@lonelyplanet.com", "coder@onesandthrees.com", "michael@guerillatactics.co.uk"]
9
+ gem.authors = ["Nicolas Overloop", "Paul Grayson", "Andy Roberts"]
10
+ gem.email = ["noverloop@gmail.com", "paul.grayson@lonelyplanet.com", "coder@onesandthrees.com"]
11
11
  gem.description = %q{Babysits long-running processes and reports progress or failures}
12
12
  gem.summary = %q{Babysits long-running processes and reports progress or failures}
13
13
  gem.homepage = ""
@@ -17,8 +17,6 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
  gem.add_dependency 'fozzie'
20
- gem.add_dependency 'timecop'
21
- gem.add_dependency 'aws-sdk'
22
20
 
23
21
  gem.add_development_dependency 'awesome_print'
24
22
  gem.add_development_dependency 'rspec'
@@ -4,17 +4,14 @@ require_relative "babysitter/version"
4
4
  require_relative "babysitter/null_logger"
5
5
  require_relative "babysitter/configuration"
6
6
  require_relative "babysitter/logging"
7
- require_relative "babysitter/logger_with_stats"
8
- require_relative "babysitter/tracker"
9
- require_relative "babysitter/monitor"
10
- require_relative "babysitter/counter"
11
- require_relative "babysitter/exception_notifiers"
12
- require 'fozzie'
7
+ require_relative "babysitter/progress_counter"
8
+ require_relative "babysitter/progress"
9
+
13
10
 
14
11
  module Babysitter
15
12
 
16
13
  def self.monitor(*args)
17
- Monitor.new(*args)
14
+ Progress.new(*args)
18
15
  end
19
16
 
20
17
  def self.configuration
@@ -29,8 +26,5 @@ module Babysitter
29
26
  configuration.logger
30
27
  end
31
28
 
32
- def self.exception_notifiers
33
- configuration.exception_notifiers
34
- end
35
29
 
36
- end
30
+ end
@@ -3,20 +3,11 @@ module Babysitter
3
3
  class Configuration
4
4
 
5
5
  attr_writer :logger
6
- attr_reader :exception_notifiers
7
-
8
- def initialize
9
- @exception_notifiers = []
10
- end
11
6
 
12
7
  def logger
13
8
  @logger ||= NullLogger.new
14
9
  end
15
10
 
16
- def enable_simple_notification_service(opts = {})
17
- @exception_notifiers << ExceptionNotifiers::SimpleNotificationService.new(opts)
18
- end
19
-
20
11
  end
21
12
 
22
- end
13
+ end
@@ -8,4 +8,4 @@ module Babysitter
8
8
 
9
9
  end
10
10
 
11
- end
11
+ end
@@ -1,5 +1,5 @@
1
1
  module Babysitter
2
- class Monitor
2
+ class Progress
3
3
  include Logging
4
4
 
5
5
  attr_accessor :stat_name
@@ -11,21 +11,21 @@ module Babysitter
11
11
  def start(msg=nil, log_every=100, &blk)
12
12
  raise ArgumentError, "Stats bucket name must not be blank" if stat_name.nil? or stat_name.empty?
13
13
  log_msg = format_log_message(msg)
14
- tracker = Tracker.new(log_every, stat_name)
14
+ counter = ProgressCounter.new(log_every, stat_name)
15
15
  logger.info "Start: #{log_msg}"
16
16
 
17
17
  begin
18
18
  result = Stats.time_to_do stat_name+[:overall] do
19
- blk.call(tracker)
19
+ blk.call(counter)
20
20
  end
21
21
  rescue Exception => e
22
- tracker.final_report rescue nil
23
- log_exception_details(log_msg, e)
22
+ counter.final_report rescue nil
23
+ log_exception_details( log_msg, e )
24
24
  raise
25
25
  end
26
26
 
27
- tracker.send_total_stats
28
- tracker.final_report
27
+ Stats.gauge stat_name+[counter.counting, :total], counter.count
28
+ counter.final_report
29
29
  logger.info "End: #{log_msg}"
30
30
  result
31
31
  end
@@ -45,13 +45,13 @@ module Babysitter
45
45
  stat_name.is_a?(Array) ? stat_name : stat_name.split('.') unless stat_name.nil? or stat_name.empty?
46
46
  end
47
47
 
48
- def log_exception_details(msg, exception)
49
- lines = ["Aborting: #{msg} due to exception #{exception.class}: #{exception}"]
50
- lines.concat(exception.backtrace) if exception.backtrace
51
-
52
- lines.each { |line| logger.error(line) }
53
- Babysitter.exception_notifiers.each { |notifier| notifier.notify(exception.class.name, lines.join("\n")) }
48
+ def log_exception_details( msg, exception )
49
+ logger.error "Aborting: #{msg} due to exception #{exception.class}: #{exception}"
50
+ if exception.backtrace
51
+ exception.backtrace.each { |line| Babysitter.logger.error " #{line}" }
52
+ end
54
53
  end
55
54
  end
56
55
 
56
+
57
57
  end
@@ -1,17 +1,16 @@
1
1
  module Babysitter
2
- class Counter
2
+ class ProgressCounter
3
3
  include Logging
4
4
 
5
- attr_reader :count, :log_every, :template, :logged_count, :stat_name, :counting
5
+ attr_reader :count, :counting, :template, :logged_count, :stat_name
6
+ attr_accessor :log_every
6
7
 
7
- attr_accessor :template
8
-
9
- def initialize(log_every, opts)
8
+ def initialize(log_every, stat_name=nil)
10
9
  @count = 0
11
10
  @logged_count = 0
11
+ @stat_name = stat_name
12
+ @counting = :iterations
12
13
  @log_every = log_every
13
- @stat_name = opts.delete(:stat_name)
14
- @counting = opts.delete(:counting)
15
14
  @timer_start = Time.now
16
15
  end
17
16
 
@@ -24,12 +23,14 @@ module Babysitter
24
23
  log_counter_messsage if log_this_time
25
24
  end
26
25
 
27
- def block_number(count)
28
- count / @log_every
26
+ def final_report
27
+ log_counter_messsage if !(template.nil? or template.empty?) && count != logged_count
29
28
  end
30
29
 
31
- def final_report?
32
- !(template.nil? or template.empty?) && count != logged_count
30
+ private
31
+
32
+ def block_number(count)
33
+ count / @log_every
33
34
  end
34
35
 
35
36
  def log_counter_messsage
@@ -52,9 +53,5 @@ module Babysitter
52
53
  Stats.count stat_name+[counting, :progress], progress unless stat_name.nil?
53
54
  end
54
55
 
55
- def send_total_stats
56
- Stats.gauge stat_name+[counting, :total], count
57
- end
58
-
59
56
  end
60
- end
57
+ end
@@ -1,3 +1,3 @@
1
1
  module Babysitter
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -11,36 +11,7 @@ module Babysitter
11
11
  subject.logger.should === null_logger
12
12
  end
13
13
 
14
- it 'has no exception notifiers' do
15
- subject.exception_notifiers.should be_empty
16
- end
17
-
18
- end
19
-
20
- describe 'enabling Amazon simple notification service integration' do
21
- let (:sns_exception_notifier) { double }
22
- let (:valid_params) { {
23
- arbritary_key: "some-value",
24
- topic_arn: "my-topic-arn"
25
- } }
26
-
27
- before :each do
28
- Babysitter::ExceptionNotifiers::SimpleNotificationService.stub(:new).and_return(sns_exception_notifier)
29
- end
30
-
31
- it 'adds an exception notifier' do
32
- subject.enable_simple_notification_service(valid_params)
33
-
34
- subject.exception_notifiers.should_not be_empty
35
- subject.exception_notifiers.first.should eql(sns_exception_notifier)
36
- end
37
-
38
- it 'configures the exception notifier' do
39
- ExceptionNotifiers::SimpleNotificationService.should_receive(:new).with(hash_including(valid_params))
40
-
41
- subject.enable_simple_notification_service(valid_params)
42
- end
43
14
  end
44
15
 
45
16
  end
46
- end
17
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Babysitter
4
- describe Monitor do
4
+ describe Progress do
5
5
  before(:each) do
6
6
  Stats.stub!(:count).with(anything, anything)
7
7
  Stats.stub!(:gauge).with(anything, anything)
@@ -9,7 +9,7 @@ module Babysitter
9
9
 
10
10
  context 'when initialized with a dot separated bucket name' do
11
11
 
12
- subject{ Monitor.new(bucket_name) }
12
+ subject{ Progress.new(bucket_name) }
13
13
  let(:bucket_name) { 'my.splendid.bucket.name' }
14
14
  let(:start_block) { Proc.new{ block_result } }
15
15
  let(:block_result) { double('block result').as_null_object }
@@ -17,7 +17,7 @@ module Babysitter
17
17
 
18
18
  describe '#completed' do
19
19
  it 'logs a done message' do
20
- Monitor.any_instance.stub(:logger).and_return(logger)
20
+ Progress.any_instance.stub(:logger).and_return(logger)
21
21
  logger.should_receive(:info).with("Done: the completed thing")
22
22
  subject.completed('the completed thing')
23
23
  end
@@ -36,26 +36,26 @@ module Babysitter
36
36
  end
37
37
 
38
38
  it 'calls logger.info with start message' do
39
- Monitor.any_instance.stub(:logger).and_return(logger)
39
+ Progress.any_instance.stub(:logger).and_return(logger)
40
40
  logger.should_receive(:info).with("Start: #{bucket_name}")
41
41
  subject.start(&start_block)
42
42
  end
43
43
 
44
44
  it 'calls logger.info with end message' do
45
- Monitor.any_instance.stub(:logger).and_return(logger)
45
+ Progress.any_instance.stub(:logger).and_return(logger)
46
46
  logger.should_receive(:info).with("End: #{bucket_name}")
47
47
  subject.start(&start_block)
48
48
  end
49
49
 
50
50
  context 'when the start method is given a message' do
51
51
  it 'calls logger.info with start message' do
52
- Monitor.any_instance.stub(:logger).and_return(logger)
52
+ Progress.any_instance.stub(:logger).and_return(logger)
53
53
  logger.should_receive(:info).with("Start: #{bucket_name} special message")
54
54
  subject.start('special message', &start_block)
55
55
  end
56
56
 
57
57
  it 'calls logger.info with end message' do
58
- Monitor.any_instance.stub(:logger).and_return(logger)
58
+ Progress.any_instance.stub(:logger).and_return(logger)
59
59
  logger.should_receive(:info).with("End: #{bucket_name} special message")
60
60
  subject.start('special message', &start_block)
61
61
  end
@@ -75,7 +75,7 @@ module Babysitter
75
75
  end
76
76
 
77
77
  it 'calls logger.info with each done message once' do
78
- Counter.any_instance.stub(:logger).and_return(logger)
78
+ ProgressCounter.any_instance.stub(:logger).and_return(logger)
79
79
  [5,10].each { |inc| logger.should_receive(:info).with( "Done: incrementing by #{inc} things").once }
80
80
  subject.start('short message', 5, &start_block_two_increments)
81
81
  end
@@ -95,7 +95,7 @@ module Babysitter
95
95
  end
96
96
 
97
97
  it 'calls logger.info with each done message once' do
98
- Counter.any_instance.stub(:logger).and_return(logger)
98
+ ProgressCounter.any_instance.stub(:logger).and_return(logger)
99
99
  [5,7].each { |inc| logger.should_receive(:info).with( "Done: incrementing by #{inc} things").once }
100
100
  subject.start('short message', 5, &start_block_seven_increments)
101
101
  end
@@ -109,120 +109,12 @@ module Babysitter
109
109
  end
110
110
 
111
111
  it 'calls logger.info with increments 18,27,36,45,54,63' do
112
- Counter.any_instance.stub(:logger).and_return(logger)
112
+ ProgressCounter.any_instance.stub(:logger).and_return(logger)
113
113
  [18,27,36,45,54,63].each { |inc| logger.should_receive(:info).with( "Done: incrementing by #{inc} things").once }
114
114
  subject.start('short message', 10, &start_block_three_increments)
115
115
  end
116
116
  end # context 'when logging every 10th call, and the block increments the counter 7 times, each with a count of 9, and identifies counted objects' do
117
117
 
118
- context "when the block logs a warning" do
119
- let(:start_block_with_warning) do
120
- Proc.new do |monitor|
121
- monitor.warn(:my_warning_bucket, 'my warning message')
122
- end
123
- end
124
- before(:each) do
125
- Babysitter.stub(:logger).and_return(logger)
126
- logger.stub!(:warn)
127
- Stats.stub!(:increment)
128
- end
129
-
130
- it 'calls logger.info with the warning message' do
131
- logger.should_receive(:warn).with( "my warning message")
132
- subject.start(&start_block_with_warning)
133
- end
134
-
135
- it 'calls Stats.count with warning bucket name' do
136
- expected_bucket_name = bucket_name.split('.') + [:my_warning_bucket, :warnings]
137
- Stats.should_receive(:increment).with(expected_bucket_name)
138
- subject.start(&start_block_with_warning)
139
- end
140
- end
141
-
142
- context "when the block logs an error" do
143
- let(:start_block_with_error) do
144
- Proc.new do |monitor|
145
- monitor.error(:my_error_bucket, 'my error message')
146
- end
147
- end
148
- before(:each) do
149
- Babysitter.stub(:logger).and_return(logger)
150
- logger.stub!(:error)
151
- Stats.stub!(:increment)
152
- end
153
-
154
- it 'calls logger.error with the error message' do
155
- logger.should_receive(:error).with( "my error message")
156
- subject.start(&start_block_with_error)
157
- end
158
-
159
- it 'calls Stats.count with error bucket name' do
160
- expected_bucket_name = bucket_name.split('.') + [:my_error_bucket, :errors]
161
- Stats.should_receive(:increment).with(expected_bucket_name)
162
- subject.start(&start_block_with_error)
163
- end
164
- end
165
-
166
- context 'when the block raises an error' do
167
- let(:error) { RuntimeError.new(error_message) }
168
- let(:backtrace) { 3.times.map { |i| "Line #{i}"} }
169
- let(:error_message) { 'A big fat error' }
170
- let(:expected_message) { "Aborting: #{bucket_name} due to exception RuntimeError: #{error_message}" }
171
- let(:start_block_with_error) { Proc.new { raise error } }
172
- before(:each) do
173
- error.stub(:backtrace).and_return(backtrace)
174
- Babysitter.stub(:logger).and_return(logger)
175
- Babysitter.stub(:exception_notifiers).and_return(2.times.map { double notify: nil })
176
- logger.stub!(:error)
177
- Stats.stub!(:increment)
178
- end
179
-
180
- it 'calls logger.error with the exeption details' do
181
- logger.should_receive(:error).with(expected_message)
182
- backtrace.each do |line|
183
- logger.should_receive(:error).with(/\w*#{line}/)
184
- end
185
-
186
- begin
187
- subject.start(&start_block_with_error)
188
- rescue
189
- end
190
- end
191
-
192
- it 'calls each exception notifier with the exception details' do
193
- message = [expected_message].concat(backtrace).join("\n")
194
-
195
- Babysitter.exception_notifiers.each do |exception_notifier|
196
- exception_notifier.should_receive(:notify).with('RuntimeError', message)
197
- end
198
-
199
- begin
200
- subject.start(&start_block_with_error)
201
- rescue
202
- end
203
- end
204
- end
205
-
206
- context 'when the block increments 2 times at intervals of 2 seconds' do
207
- let(:start_block_for_timing) do
208
- Proc.new do |counter|
209
- 2.times do
210
- Timecop.travel(Time.now+2) # move on 2 seconds
211
- counter.inc('doing increment',1)
212
- end
213
- end
214
- end
215
- before(:each) { Timecop.travel(Time.now) }
216
- after(:each) { Timecop.return }
217
-
218
- it 'calculates a rate close to 0.5 per second' do
219
- Counter.any_instance.should_receive(:send_rate_stats) do |rate|
220
- rate.should be_within(0.01).of(0.5)
221
- end
222
- subject.start(&start_block_for_timing)
223
- end
224
- end
225
-
226
118
  end
227
119
 
228
120
  end
@@ -5,8 +5,8 @@
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  require 'awesome_print'
8
+ require 'fozzie'
8
9
  require 'babysitter'
9
- require 'timecop'
10
10
 
11
11
  RSpec.configure do |config|
12
12
  config.treat_symbols_as_metadata_keys_with_true_values = true
metadata CHANGED
@@ -1,18 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: babysitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nicolas Overloop
9
9
  - Paul Grayson
10
10
  - Andy Roberts
11
- - Mike Wagg
12
11
  autorequire:
13
12
  bindir: bin
14
13
  cert_chain: []
15
- date: 2013-02-13 00:00:00.000000000 Z
14
+ date: 2013-01-15 00:00:00.000000000 Z
16
15
  dependencies:
17
16
  - !ruby/object:Gem::Dependency
18
17
  name: fozzie
@@ -30,38 +29,6 @@ dependencies:
30
29
  - - ! '>='
31
30
  - !ruby/object:Gem::Version
32
31
  version: '0'
33
- - !ruby/object:Gem::Dependency
34
- name: timecop
35
- requirement: !ruby/object:Gem::Requirement
36
- none: false
37
- requirements:
38
- - - ! '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- type: :runtime
42
- prerelease: false
43
- version_requirements: !ruby/object:Gem::Requirement
44
- none: false
45
- requirements:
46
- - - ! '>='
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- - !ruby/object:Gem::Dependency
50
- name: aws-sdk
51
- requirement: !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
54
- - - ! '>='
55
- - !ruby/object:Gem::Version
56
- version: '0'
57
- type: :runtime
58
- prerelease: false
59
- version_requirements: !ruby/object:Gem::Requirement
60
- none: false
61
- requirements:
62
- - - ! '>='
63
- - !ruby/object:Gem::Version
64
- version: '0'
65
32
  - !ruby/object:Gem::Dependency
66
33
  name: awesome_print
67
34
  requirement: !ruby/object:Gem::Requirement
@@ -99,7 +66,6 @@ email:
99
66
  - noverloop@gmail.com
100
67
  - paul.grayson@lonelyplanet.com
101
68
  - coder@onesandthrees.com
102
- - michael@guerillatactics.co.uk
103
69
  executables: []
104
70
  extensions: []
105
71
  extra_rdoc_files: []
@@ -112,20 +78,13 @@ files:
112
78
  - babysitter.gemspec
113
79
  - lib/babysitter.rb
114
80
  - lib/babysitter/configuration.rb
115
- - lib/babysitter/counter.rb
116
- - lib/babysitter/exception_notifiers.rb
117
- - lib/babysitter/exception_notifiers/simple_notification_service.rb
118
- - lib/babysitter/logger_with_stats.rb
119
81
  - lib/babysitter/logging.rb
120
- - lib/babysitter/monitor.rb
121
82
  - lib/babysitter/null_logger.rb
122
- - lib/babysitter/tracker.rb
83
+ - lib/babysitter/progress.rb
84
+ - lib/babysitter/progress_counter.rb
123
85
  - lib/babysitter/version.rb
124
86
  - spec/lib/babysitter/configuration_spec.rb
125
- - spec/lib/babysitter/exception_notifiers/simple_notification_service_spec.rb
126
- - spec/lib/babysitter/monitor_spec.rb
127
- - spec/lib/babysitter/tracker_spec.rb
128
- - spec/lib/babysitter_spec.rb
87
+ - spec/lib/babysitter/progress_spec.rb
129
88
  - spec/spec_helper.rb
130
89
  homepage: ''
131
90
  licenses: []
@@ -153,8 +112,5 @@ specification_version: 3
153
112
  summary: Babysits long-running processes and reports progress or failures
154
113
  test_files:
155
114
  - spec/lib/babysitter/configuration_spec.rb
156
- - spec/lib/babysitter/exception_notifiers/simple_notification_service_spec.rb
157
- - spec/lib/babysitter/monitor_spec.rb
158
- - spec/lib/babysitter/tracker_spec.rb
159
- - spec/lib/babysitter_spec.rb
115
+ - spec/lib/babysitter/progress_spec.rb
160
116
  - spec/spec_helper.rb
@@ -1 +0,0 @@
1
- require_relative "exception_notifiers/simple_notification_service"
@@ -1,42 +0,0 @@
1
- require 'aws-sdk'
2
-
3
- module Babysitter
4
- module ExceptionNotifiers
5
- class SimpleNotificationService
6
- def initialize(opts = {})
7
- @topic_arn = opts.delete(:topic_arn)
8
- @get_credentials = opts.delete(:credentials)
9
- raise ArgumentError, "topic_arn is required." if @topic_arn.nil?
10
- raise ArgumentError, "credentials is required and must be a Proc." if @get_credentials.nil? || !@get_credentials.is_a?(Proc)
11
-
12
- validate_topic
13
- end
14
-
15
- def notify(subject, msg)
16
- topic.publish(msg, subject: sanitise_subject(subject))
17
- end
18
-
19
- private
20
-
21
- def sns
22
- AWS::SNS.new(@get_credentials.call)
23
- end
24
-
25
- def topic
26
- sns.topics[@topic_arn]
27
- end
28
-
29
- def sanitise_subject(subject)
30
- sanitised = /\s*([^\x00-\x1F]*)/.match(subject)[1]
31
-
32
- return "(no subject)" if sanitised.empty?
33
- return sanitised[0..96] + "..." if sanitised.size > 100
34
- sanitised
35
- end
36
-
37
- def validate_topic
38
- topic.display_name
39
- end
40
- end
41
- end
42
- end
@@ -1,43 +0,0 @@
1
- module Babysitter
2
- class LoggerWithStats
3
- include Logging
4
-
5
- attr_accessor :stat_name_prefix
6
-
7
- STATS_SUFFIX_BY_METHOD = { warn: :warnings, error: :errors, fatal: :fatals }
8
-
9
- def initialize(stat_name_prefix)
10
- @stat_name_prefix = stat_name_prefix
11
- end
12
-
13
- def method_missing(meth, *opts)
14
- unless %w{ info debug error fatal}.include?(meth.to_s)
15
- super
16
- return
17
- end
18
- stats_suffix_from_method(meth).tap{ |suffix| increment(suffix) if suffix }
19
- logger.send(meth, *opts)
20
- end
21
-
22
- def warn(*opts)
23
- increment(stats_suffix_from_method(:warn))
24
- logger.warn(*opts)
25
- end
26
-
27
- private
28
-
29
- def stats_suffix_from_method(meth)
30
- STATS_SUFFIX_BY_METHOD[meth]
31
- end
32
-
33
- def increment(stat_name_suffix)
34
- Stats.increment full_stat_name(stat_name_suffix)
35
- end
36
-
37
- def full_stat_name(stat_name_suffix)
38
- stat_name_prefix + [stat_name_suffix]
39
- end
40
-
41
- end
42
-
43
- end
@@ -1,52 +0,0 @@
1
- module Babysitter
2
- class Tracker
3
- include Logging
4
-
5
- attr_reader :counting, :stat_name, :counter
6
- attr_accessor :log_every
7
-
8
- def initialize(log_every, stat_name=nil)
9
- @stat_name = stat_name
10
- @counting = :iterations
11
- @log_every = log_every
12
- @counter = Counter.new(log_every, stat_name: stat_name, counting: counting)
13
- end
14
-
15
- def inc(*args)
16
- counter.inc(*args)
17
- end
18
-
19
- def count
20
- counter.count
21
- end
22
-
23
- def final_report
24
- counter.log_counter_messsage if counter.final_report?
25
- end
26
-
27
- def warn(topic_name, message)
28
- logger_with_stats_for(topic_name).warn(message)
29
- end
30
-
31
- def error(topic_name, message)
32
- logger_with_stats_for(topic_name).error(message)
33
- end
34
-
35
- def send_total_stats
36
- counter.send_total_stats
37
- end
38
-
39
- def logger_with_stats_for(topic_name)
40
- @loggers ||= {}
41
- @loggers[topic_name] ||= LoggerWithStats.new(stats_prefix_for_topic(topic_name))
42
- end
43
-
44
- private
45
-
46
- def stats_prefix_for_topic(topic_name)
47
- stat_name+[topic_name]
48
- end
49
-
50
- end
51
-
52
- end
@@ -1,105 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Babysitter
4
- module ExceptionNotifiers
5
- describe SimpleNotificationService do
6
- subject { SimpleNotificationService.new(valid_opts) }
7
- let(:get_credentials_lambda) { -> {
8
- {
9
- access_key_id: 'an-access-key-id',
10
- secret_access_key: 'a-secret-address-key',
11
- }
12
- } }
13
- let(:valid_opts) { {
14
- credentials: get_credentials_lambda,
15
- topic_arn: 'my-topic-arn'
16
- } }
17
- let(:sns) { double :sns, topics: { 'my-topic-arn' => topic } }
18
- let(:topic) { double :topic, publish: nil, display_name: "A topic" }
19
- before :each do
20
- AWS::SNS.stub(:new).and_return(sns)
21
- end
22
-
23
- it 'requires a topic_arn' do
24
- valid_opts.delete :topic_arn
25
- -> { subject }.should raise_error(ArgumentError, /topic_arn/)
26
- end
27
-
28
- it "requires credentials" do
29
- valid_opts.delete :credentials
30
- -> { subject }.should raise_error(ArgumentError, /credentials/)
31
- end
32
-
33
- it 'requires a block to retrieve AWS credentials' do
34
- valid_opts[:credentials] = {}
35
- -> { subject }.should raise_error(ArgumentError, /credentials/)
36
- end
37
-
38
- it 'uses the options passed to configure the credentials for sns' do
39
- AWS::SNS.should_receive(:new).with(get_credentials_lambda.call)
40
- subject
41
- end
42
-
43
- it 'validates the topic by checking it has a display name' do
44
- topic.should_receive(:display_name)
45
- subject
46
- end
47
-
48
- describe '.notify' do
49
- let(:message) { "the message" }
50
- let(:notification_subject) { "the subject" }
51
-
52
- it 'again uses the options passed to configure the credentials for sns' do
53
- AWS::SNS.should_receive(:new).with(get_credentials_lambda.call).twice
54
- subject.notify(notification_subject, message)
55
- end
56
-
57
- it 'publishes to the topic specified' do
58
- topic.should_receive(:publish)
59
-
60
- subject.notify(notification_subject, message)
61
- end
62
-
63
- it 'publishes the message' do
64
- topic.should_receive(:publish).with(message, hash_including(subject: notification_subject))
65
-
66
- subject.notify(notification_subject, message)
67
- end
68
-
69
- it "shortens the subject to 100 characters if necessary" do
70
- shortened_subject = 97.times.map { "x" }.join + "..."
71
- original_subject = 101.times.map { "x" }.join
72
-
73
- topic.should_receive(:publish).with(message, hash_including(subject: shortened_subject))
74
-
75
- subject.notify(original_subject, message)
76
- end
77
-
78
- it "strips control characters" do
79
- expected_subject = "this is the subject"
80
- original_subject = "#{expected_subject}"
81
- 32.times.each { |code| original_subject << code.chr }
82
-
83
- topic.should_receive(:publish).with(message, hash_including(subject: expected_subject))
84
-
85
- subject.notify(original_subject, message)
86
- end
87
-
88
- it "strips leading whitespace" do
89
- expected_subject = "this is the subject"
90
- original_subject = " #{expected_subject}"
91
-
92
- topic.should_receive(:publish).with(message, hash_including(subject: expected_subject))
93
-
94
- subject.notify(original_subject, message)
95
- end
96
-
97
- it "handles empty subject" do
98
- topic.should_receive(:publish).with(message, hash_including(subject: "(no subject)"))
99
-
100
- subject.notify("", message)
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,81 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Babysitter
4
- describe Tracker do
5
-
6
- subject{ Tracker.new(log_interval, stat_bucket_prefix) }
7
- let(:log_interval) { 5 }
8
- let(:stat_bucket_prefix) { [:my, :stat, :bucket, :prefix] }
9
- let(:logger) { double('boring old vanilla babysitter logger') }
10
- before(:each) do
11
- Babysitter.stub(:logger).and_return(logger)
12
- end
13
-
14
- describe '#logger_with_stats_for' do
15
-
16
- it 'returns the same logger when passed the same symbol twice' do
17
- l1 = subject.logger_with_stats_for(:lodgings)
18
- l2 = subject.logger_with_stats_for(:lodgings)
19
- l1.should be_equal(l2)
20
- end
21
-
22
- it 'returns different loggers when passed different symbols' do
23
- l = subject.logger_with_stats_for(:lodgings)
24
- p = subject.logger_with_stats_for(:places)
25
- l.should_not be_equal(p)
26
- end
27
-
28
- end # describe '#logger_with_stats' do
29
-
30
- describe 'logger returned by logger_with_stats_for(some_topic)' do
31
- subject{ Tracker.new(log_interval, stat_bucket_prefix).logger_with_stats_for(some_topic) }
32
- let(:some_topic) { :some_topic }
33
- let(:text_of_the_message) {'the message we want in the logs'}
34
-
35
- { warn: :warnings, error: :errors, fatal: :fatals }.each do |message_type, stats_bucket_suffix|
36
- describe "##{message_type}" do
37
- before(:each) do
38
- logger.stub(message_type)
39
- Stats.stub!(:increment)
40
- end
41
-
42
- it 'logs the message' do
43
- logger.should_receive(message_type).with(text_of_the_message)
44
- subject.send(message_type, text_of_the_message)
45
- end
46
-
47
- it 'sends the stats' do
48
- expected_stats_bucket = stat_bucket_prefix + [some_topic, stats_bucket_suffix]
49
- Stats.should_receive(:increment).with(expected_stats_bucket)
50
- subject.send(message_type, text_of_the_message)
51
- end
52
- end
53
-
54
- end
55
-
56
- [:info, :debug].each do |message_type|
57
- describe "##{message_type}" do
58
- before(:each) do
59
- logger.stub(message_type)
60
- Stats.stub!(:increment)
61
- end
62
-
63
- it 'logs the message' do
64
- logger.should_receive(message_type).with(text_of_the_message)
65
- subject.send(message_type, text_of_the_message)
66
- end
67
-
68
- it 'sends no stats' do
69
- Stats.should_not_receive(:increment)
70
- subject.send(message_type, text_of_the_message)
71
- end
72
- end
73
-
74
- end
75
-
76
- end # describe 'logger returned by logger_with_stats_for(:something)' do
77
-
78
- end
79
- end
80
-
81
-
@@ -1,50 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Babysitter do
4
-
5
- describe '.monitor' do
6
- it 'returns an instance of Monitor' do
7
- Babysitter.monitor.should be_an_instance_of(Babysitter::Monitor)
8
- end
9
- end
10
-
11
- describe '.configuration' do
12
- it 'returns an instance of Configuration' do
13
- Babysitter.configuration.should be_an_instance_of(Babysitter::Configuration)
14
- end
15
-
16
- it 'returns the same instance every time' do
17
- c = Babysitter.configuration
18
- Babysitter.configuration.should eql(c)
19
- end
20
- end
21
-
22
- describe '.configure' do
23
- describe 'object yielded to block' do
24
- it 'is the unique configuration object' do
25
- Babysitter.configure do |c|
26
- c.should eql(Babysitter.configuration)
27
- end
28
- end
29
- end
30
- end
31
-
32
- describe '.logger' do
33
- let(:configured_logger) { double('configured logger').as_null_object }
34
-
35
- it 'returns the logger from the configuration' do
36
- Babysitter::Configuration.any_instance.stub(:logger).and_return(configured_logger)
37
- Babysitter.logger.should eql(configured_logger)
38
- end
39
- end
40
-
41
- describe '.exception_notifiers' do
42
- let(:exception_notifiers) { double('notifiers').as_null_object}
43
-
44
- it 'returns the notifiers from the configuration' do
45
- Babysitter::Configuration.any_instance.stub(:exception_notifiers).and_return(exception_notifiers)
46
- Babysitter.exception_notifiers.should eql(exception_notifiers)
47
- end
48
- end
49
-
50
- end