babysitter 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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", git: 'git@github.com:lonelyplanet/babysitter.git'
10
+ gem "babysitter"
11
11
 
12
12
  And then execute:
13
13
 
@@ -17,6 +17,7 @@ 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'
20
21
 
21
22
  gem.add_development_dependency 'awesome_print'
22
23
  gem.add_development_dependency 'rspec'
@@ -4,14 +4,15 @@ 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/progress_counter"
8
7
  require_relative "babysitter/progress"
9
-
8
+ require_relative "babysitter/monitor"
9
+ require_relative "babysitter/counter"
10
+ require 'fozzie'
10
11
 
11
12
  module Babysitter
12
13
 
13
14
  def self.monitor(*args)
14
- Progress.new(*args)
15
+ Monitor.new(*args)
15
16
  end
16
17
 
17
18
  def self.configuration
@@ -27,4 +28,4 @@ module Babysitter
27
28
  end
28
29
 
29
30
 
30
- end
31
+ end
@@ -1,16 +1,17 @@
1
1
  module Babysitter
2
- class ProgressCounter
2
+ class Counter
3
3
  include Logging
4
4
 
5
- attr_reader :count, :counting, :template, :logged_count, :stat_name
6
- attr_accessor :log_every
5
+ attr_reader :count, :log_every, :template, :logged_count, :stat_name, :counting
7
6
 
8
- def initialize(log_every, stat_name=nil)
7
+ attr_accessor :template
8
+
9
+ def initialize(log_every, opts)
9
10
  @count = 0
10
11
  @logged_count = 0
11
- @stat_name = stat_name
12
- @counting = :iterations
13
12
  @log_every = log_every
13
+ @stat_name = opts.delete(:stat_name)
14
+ @counting = opts.delete(:counting)
14
15
  @timer_start = Time.now
15
16
  end
16
17
 
@@ -23,16 +24,14 @@ module Babysitter
23
24
  log_counter_messsage if log_this_time
24
25
  end
25
26
 
26
- def final_report
27
- log_counter_messsage if !(template.nil? or template.empty?) && count != logged_count
28
- end
29
-
30
- private
31
-
32
27
  def block_number(count)
33
28
  count / @log_every
34
29
  end
35
30
 
31
+ def final_report?
32
+ !(template.nil? or template.empty?) && count != logged_count
33
+ end
34
+
36
35
  def log_counter_messsage
37
36
  logger.info( "Done: #{template.gsub("{{count}}", count.to_s)}" )
38
37
  send_progress_stats(count - logged_count)
@@ -53,5 +52,9 @@ module Babysitter
53
52
  Stats.count stat_name+[counting, :progress], progress unless stat_name.nil?
54
53
  end
55
54
 
55
+ def send_total_stats
56
+ Stats.gauge stat_name+[counting, :total], count
57
+ end
58
+
56
59
  end
57
- end
60
+ end
@@ -0,0 +1,56 @@
1
+ module Babysitter
2
+ class Monitor
3
+ include Logging
4
+
5
+ attr_accessor :stat_name
6
+
7
+ def initialize(stat_name=nil)
8
+ @stat_name = convert_stat_name_to_array(stat_name)
9
+ end
10
+
11
+ def start(msg=nil, log_every=100, &blk)
12
+ raise ArgumentError, "Stats bucket name must not be blank" if stat_name.nil? or stat_name.empty?
13
+ log_msg = format_log_message(msg)
14
+ progress = Progress.new(log_every, stat_name)
15
+ logger.info "Start: #{log_msg}"
16
+
17
+ begin
18
+ result = Stats.time_to_do stat_name+[:overall] do
19
+ blk.call(progress)
20
+ end
21
+ rescue Exception => e
22
+ progress.final_report rescue nil
23
+ log_exception_details( log_msg, e )
24
+ raise
25
+ end
26
+
27
+ progress.send_total_stats
28
+ progress.final_report
29
+ logger.info "End: #{log_msg}"
30
+ result
31
+ end
32
+
33
+ def completed(msg)
34
+ logger.info "Done: #{msg}"
35
+ end
36
+
37
+ private
38
+
39
+ def format_log_message(msg)
40
+ log_msg = stat_name.join('.')
41
+ [log_msg,msg].compact.join(' ')
42
+ end
43
+
44
+ def convert_stat_name_to_array(stat_name)
45
+ stat_name.is_a?(Array) ? stat_name : stat_name.split('.') unless stat_name.nil? or stat_name.empty?
46
+ end
47
+
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| logger.error " #{line}" }
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -2,56 +2,51 @@ module Babysitter
2
2
  class Progress
3
3
  include Logging
4
4
 
5
- attr_accessor :stat_name
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
6
18
 
7
- def initialize(stat_name=nil)
8
- @stat_name = convert_stat_name_to_array(stat_name)
19
+ def count
20
+ counter.count
9
21
  end
10
22
 
11
- def start(msg=nil, log_every=100, &blk)
12
- raise ArgumentError, "Stats bucket name must not be blank" if stat_name.nil? or stat_name.empty?
13
- log_msg = format_log_message(msg)
14
- counter = ProgressCounter.new(log_every, stat_name)
15
- logger.info "Start: #{log_msg}"
23
+ def final_report
24
+ counter.log_counter_messsage if counter.final_report?
25
+ end
16
26
 
17
- begin
18
- result = Stats.time_to_do stat_name+[:overall] do
19
- blk.call(counter)
20
- end
21
- rescue Exception => e
22
- counter.final_report rescue nil
23
- log_exception_details( log_msg, e )
24
- raise
25
- end
27
+ def warn(partial_bucket_name, message)
28
+ logger.warn(message)
29
+ send_warning_stat(partial_bucket_name)
30
+ end
26
31
 
27
- Stats.gauge stat_name+[counter.counting, :total], counter.count
28
- counter.final_report
29
- logger.info "End: #{log_msg}"
30
- result
32
+ def error(partial_bucket_name, message)
33
+ logger.error(message)
34
+ send_error_stat(partial_bucket_name)
31
35
  end
32
36
 
33
- def completed(msg)
34
- logger.info "Done: #{msg}"
37
+ def send_total_stats
38
+ counter.send_total_stats
35
39
  end
36
40
 
37
41
  private
38
42
 
39
- def format_log_message(msg)
40
- log_msg = stat_name.join('.')
41
- [log_msg,msg].compact.join(' ')
43
+ def send_warning_stat(partial_bucket_name)
44
+ Stats.increment stat_name+[partial_bucket_name, :warnings] unless stat_name.nil?
42
45
  end
43
46
 
44
- def convert_stat_name_to_array(stat_name)
45
- stat_name.is_a?(Array) ? stat_name : stat_name.split('.') unless stat_name.nil? or stat_name.empty?
47
+ def send_error_stat(partial_bucket_name)
48
+ Stats.increment stat_name+[partial_bucket_name, :errors] unless stat_name.nil?
46
49
  end
47
50
 
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
53
- end
54
51
  end
55
-
56
-
57
52
  end
@@ -1,3 +1,3 @@
1
1
  module Babysitter
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Babysitter
4
- describe Progress do
4
+ describe Monitor 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{ Progress.new(bucket_name) }
12
+ subject{ Monitor.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
- Progress.any_instance.stub(:logger).and_return(logger)
20
+ Monitor.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
- Progress.any_instance.stub(:logger).and_return(logger)
39
+ Monitor.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
- Progress.any_instance.stub(:logger).and_return(logger)
45
+ Monitor.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
- Progress.any_instance.stub(:logger).and_return(logger)
52
+ Monitor.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
- Progress.any_instance.stub(:logger).and_return(logger)
58
+ Monitor.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
- ProgressCounter.any_instance.stub(:logger).and_return(logger)
78
+ Counter.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
- ProgressCounter.any_instance.stub(:logger).and_return(logger)
98
+ Counter.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,12 +109,74 @@ module Babysitter
109
109
  end
110
110
 
111
111
  it 'calls logger.info with increments 18,27,36,45,54,63' do
112
- ProgressCounter.any_instance.stub(:logger).and_return(logger)
112
+ Counter.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
+
125
+ it 'calls logger.info with the warning message' do
126
+ Progress.any_instance.stub(:logger).and_return(logger)
127
+ logger.should_receive(:warn).with( "my warning message")
128
+ Stats.stub!(:increment)
129
+ subject.start(&start_block_with_warning)
130
+ end
131
+
132
+ it 'calls Stats.count with warning bucket name' do
133
+ expected_bucket_name = bucket_name.split('.') + [:my_warning_bucket, :warnings]
134
+ Stats.should_receive(:increment).with(expected_bucket_name)
135
+ subject.start(&start_block_with_warning)
136
+ end
137
+ end
138
+
139
+ context "when the block logs an error" do
140
+ let(:start_block_with_error) do
141
+ Proc.new do |monitor|
142
+ monitor.error(:my_error_bucket, 'my error message')
143
+ end
144
+ end
145
+
146
+ it 'calls logger.error with the error message' do
147
+ Progress.any_instance.stub(:logger).and_return(logger)
148
+ logger.should_receive(:error).with( "my error message")
149
+ Stats.stub!(:increment)
150
+ subject.start(&start_block_with_error)
151
+ end
152
+
153
+ it 'calls Stats.count with error bucket name' do
154
+ expected_bucket_name = bucket_name.split('.') + [:my_error_bucket, :errors]
155
+ Stats.should_receive(:increment).with(expected_bucket_name)
156
+ subject.start(&start_block_with_error)
157
+ end
158
+ end
159
+
160
+ context 'when the block increments 2 times at intervals of 2 seconds' do
161
+ let(:start_block_for_timing) do
162
+ Proc.new do |counter|
163
+ 2.times do
164
+ Timecop.travel(Time.now+2) # move on 2 seconds
165
+ counter.inc('doing increment',1)
166
+ end
167
+ end
168
+ end
169
+ before(:each) { Timecop.travel(Time.now) }
170
+ after(:each) { Timecop.return }
171
+
172
+ it 'calculates a rate close to 0.5 per second' do
173
+ Counter.any_instance.should_receive(:send_rate_stats) do |rate|
174
+ rate.should be_within(0.01).of(0.5)
175
+ end
176
+ subject.start(&start_block_for_timing)
177
+ end
178
+ end
179
+
118
180
  end
119
181
 
120
182
  end
@@ -0,0 +1,41 @@
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
+ 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'
9
8
  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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: babysitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-01-15 00:00:00.000000000 Z
14
+ date: 2013-01-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: fozzie
@@ -29,6 +29,22 @@ dependencies:
29
29
  - - ! '>='
30
30
  - !ruby/object:Gem::Version
31
31
  version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: timecop
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
32
48
  - !ruby/object:Gem::Dependency
33
49
  name: awesome_print
34
50
  requirement: !ruby/object:Gem::Requirement
@@ -78,13 +94,15 @@ files:
78
94
  - babysitter.gemspec
79
95
  - lib/babysitter.rb
80
96
  - lib/babysitter/configuration.rb
97
+ - lib/babysitter/counter.rb
81
98
  - lib/babysitter/logging.rb
99
+ - lib/babysitter/monitor.rb
82
100
  - lib/babysitter/null_logger.rb
83
101
  - lib/babysitter/progress.rb
84
- - lib/babysitter/progress_counter.rb
85
102
  - lib/babysitter/version.rb
86
103
  - spec/lib/babysitter/configuration_spec.rb
87
- - spec/lib/babysitter/progress_spec.rb
104
+ - spec/lib/babysitter/monitor_spec.rb
105
+ - spec/lib/babysitter_spec.rb
88
106
  - spec/spec_helper.rb
89
107
  homepage: ''
90
108
  licenses: []
@@ -106,11 +124,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
124
  version: '0'
107
125
  requirements: []
108
126
  rubyforge_project:
109
- rubygems_version: 1.8.24
127
+ rubygems_version: 1.8.22
110
128
  signing_key:
111
129
  specification_version: 3
112
130
  summary: Babysits long-running processes and reports progress or failures
113
131
  test_files:
114
132
  - spec/lib/babysitter/configuration_spec.rb
115
- - spec/lib/babysitter/progress_spec.rb
133
+ - spec/lib/babysitter/monitor_spec.rb
134
+ - spec/lib/babysitter_spec.rb
116
135
  - spec/spec_helper.rb