babysitter 0.0.2 → 0.0.4

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", 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