babysitter 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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