birling 0.1.0

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem "bundler"
5
+ gem "jeweler"
6
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Scott Tadman, The Working Group.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # birling
2
+
3
+ A replacement for Logger that offers more robust handling of log rotation.
4
+
5
+ The built-in logger supports log rotation on a daily, weekly or monthly basis,
6
+ but not with more fine-grained control. Birling will allow rotation by hour,
7
+ by day, or by an arbitrary amount of time expressed in seconds.
8
+
9
+ Additionally, Birling will automatically remove old log files. These can be
10
+ pruned off by age, by retaining a minimum number of them, or a combination of
11
+ both.
12
+
13
+ ## Example
14
+
15
+ The interface is very similar to the [built in logger](http://rubygems.org/gems/logger)
16
+ facility that ships with Ruby:
17
+
18
+ ```ruby
19
+ logger = Birling::Logger.new('test.log')
20
+
21
+ logger.info("Application starting up.")
22
+ logger.debug("application_init()")
23
+ ```
24
+
25
+ A short-hand method is available:
26
+
27
+ ```ruby
28
+ logger = Birling.open('test.log')
29
+ ```
30
+
31
+ Log rotation parameters are quite flexible. For example, to retain a maximum
32
+ of ten hourly logs:
33
+
34
+ ```ruby
35
+ logger = Birling.open(
36
+ 'test.log',
37
+ :period => :hourly,
38
+ :retain_count => 10
39
+ )
40
+ ```
41
+
42
+ Alternatively the retention period can be expressed in terms of time where
43
+ log files that could have been created by this logger which are older than
44
+ that period will be removed:
45
+
46
+ ```ruby
47
+ logger = Birling.open(
48
+ 'test.log',
49
+ :period => :hourly,
50
+ :retain_period => 10 * 3600
51
+ )
52
+ ```
53
+
54
+ The format of the resulting log-file can be adjusted by supplying a formatter.
55
+ Several arguments passed to the formatter's `call` method, so a `lambda`, a
56
+ `module` or an object instance could be used for this purpose.
57
+
58
+ Example:
59
+
60
+ ```ruby
61
+ logger = Birling.open(
62
+ 'test.log',
63
+ :formatter => lambda { |severity, time, program, message| "#{time}> #{message}\n" }
64
+ )
65
+ ```
66
+
67
+ Note that the formatter is responsible for introducing any line-feeds into
68
+ the resulting output stream. This gives the formatter complete control over
69
+ what is written to the log.
70
+
71
+ ## Limitations
72
+
73
+ The log rotation feature, for reasons that should be obvious, will not work
74
+ on loggers that are created with an existing file-handle. For example, when
75
+ using `STDOUT` the logger will not rotate.
76
+
77
+ ## Copyright
78
+
79
+ Copyright (c) 2011-2012 Scott Tadman, The Working Group Inc.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'rake'
13
+ require 'jeweler'
14
+
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "birling"
17
+ gem.homepage = "http://github.com/twg/birling"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{Logger with simple log rotation system}
20
+ gem.description = %Q{Mostly drop-in replacement for Logger with a more robust log rotation facility}
21
+ gem.email = "github@tadman.ca"
22
+ gem.authors = [ "Scott Tadman" ]
23
+ end
24
+
25
+ Jeweler::RubygemsDotOrgTasks.new
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,15 @@
1
+ module Birling::Formatter
2
+ # == Constants ============================================================
3
+
4
+ TIME_FORMAT_DEFAULT = '%Y-%m-%d %H:%M:%S'.freeze
5
+
6
+ # == Module Methods =======================================================
7
+
8
+ def self.call(severity, time, program, message)
9
+ if (program)
10
+ "[#{time.strftime(TIME_FORMAT_DEFAULT)}] <#{program}> #{message}"
11
+ else
12
+ "[#{time.strftime(TIME_FORMAT_DEFAULT)}] #{message}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ class Birling::Log < File
2
+ # == Constants ============================================================
3
+
4
+ # == Class Methods ========================================================
5
+
6
+ def self.open(log, mode = nil)
7
+ case (log)
8
+ when IO
9
+ yield(log) if (block_given?)
10
+
11
+ log
12
+ when String
13
+ io = new(log, mode || 'a')
14
+
15
+ yield(io) if (block_given?)
16
+
17
+ io
18
+ end
19
+ end
20
+
21
+ # == Instance Methods =====================================================
22
+
23
+ def size
24
+ self.stat.size
25
+ end
26
+
27
+ def create_time
28
+ self.stat.ctime
29
+ end
30
+
31
+ def age(relative_to = nil)
32
+ (relative_to || Time.now) - self.stat.ctime
33
+ end
34
+ end
@@ -0,0 +1,257 @@
1
+ class Birling::Logger
2
+ # == Constants ============================================================
3
+
4
+ # These level constants are the same as the syslog system utility
5
+ SEVERITY = {
6
+ :emergency => EMERGENCY = 0,
7
+ :alert => ALERT = 1,
8
+ :critical => CRITICAL = 2,
9
+ :error => ERROR = 3,
10
+ :warning => WARNING = 4,
11
+ :notice => NOTICE = 5,
12
+ :info => INFO = 6,
13
+ :debug => DEBUG = 7,
14
+ :unknown => UNKNOWN = 999
15
+ }.freeze
16
+
17
+ DEFAULT_SEVERITY = UNKNOWN
18
+
19
+ SEVERITY_LABEL = SEVERITY.invert.freeze
20
+
21
+ PATH_TIME_DEFAULT = {
22
+ :hourly => '%Y%m%d%H'.freeze,
23
+ :daily => '%Y%m%d'.freeze,
24
+ :default => '%s'.freeze
25
+ }.freeze
26
+
27
+ # == Properties ===========================================================
28
+
29
+ attr_reader :severity
30
+ attr_accessor :formatter
31
+ attr_accessor :program
32
+ attr_accessor :time_source
33
+ attr_reader :path
34
+ attr_reader :path_format
35
+ attr_reader :path_time_format
36
+ attr_reader :current_path
37
+ attr_reader :retain_count
38
+ attr_reader :retain_period
39
+ attr_reader :period
40
+ attr_reader :rotation_time
41
+
42
+ # == Class Methods ========================================================
43
+
44
+ def self.severity(value)
45
+ case (value)
46
+ when Symbol
47
+ SEVERITY[value] or DEFAULT_SEVERITY
48
+ when String
49
+ SEVERITY[value.to_sym] or DEFAULT_SEVERITY
50
+ when Fixnum
51
+ SEVERITY_LABEL[value] and value or DEFAULT_SEVERITY
52
+ else
53
+ DEFAULT_SEVERITY
54
+ end
55
+ end
56
+
57
+ # == Instance Methods =====================================================
58
+
59
+ def initialize(log, options = nil)
60
+ @period = (options and options[:period])
61
+ @severity = self.class.severity(options && options[:severity])
62
+ @retain_count = (options and options[:retain_count])
63
+ @retain_period = (options and options[:retain_period])
64
+ @formatter = (options and options[:formatter] or Birling::Formatter)
65
+ @program = (options and options[:program] or nil)
66
+ @time_source = (options and options[:time_source] or Time)
67
+ @path_format = (options and options[:path_format])
68
+
69
+ case (log)
70
+ when IO, StringIO
71
+ @log = log
72
+ when String
73
+ @path = log
74
+ end
75
+
76
+ if (@path and @period)
77
+ @rotation_time = self.next_rotation_time
78
+
79
+ @path_time_format = (PATH_TIME_DEFAULT[@period] or PATH_TIME_DEFAULT[:default])
80
+
81
+ @path_format ||=
82
+ @path.sub(/\.(\w+)$/) do |s|
83
+ '.' + @path_time_format + '.' + $1
84
+ end
85
+ end
86
+
87
+ if (@path and !@log)
88
+ self.log_open!
89
+ end
90
+
91
+ yield(self) if (block_given?)
92
+ end
93
+
94
+ def severity=(value)
95
+ @severity = self.class.severity(value)
96
+ end
97
+
98
+ def can_rotate?
99
+ !!@path
100
+ end
101
+
102
+ def size
103
+ @log and @log.respond_to
104
+ end
105
+
106
+ def retain=(value)
107
+ @retain = value ? value.to_i : nil
108
+
109
+ if (@retain_period and @retain_period <= 0)
110
+ @retain_period = nil
111
+ end
112
+
113
+ @retain_period
114
+ end
115
+
116
+ def log(level, message = nil, program = nil)
117
+ return unless (@log)
118
+
119
+ level = self.class.severity(level)
120
+ program ||= @program
121
+
122
+ self.check_log_rotation!
123
+
124
+ @log.write(@formatter.call(level, @time_source.now, program, message))
125
+ end
126
+ alias_method :add, :log
127
+
128
+ def <<(message)
129
+ return unless (@log)
130
+
131
+ self.check_log_rotation!
132
+
133
+ @log.write(message)
134
+ end
135
+
136
+ SEVERITY.each do |name, level|
137
+ define_method(:"#{name}?") do
138
+ @severity >= level
139
+ end
140
+
141
+ define_method(name) do |message = nil, program = nil|
142
+ return unless (@log and @severity >= level)
143
+
144
+ program ||= @program
145
+
146
+ if (!message and block_given?)
147
+ message = yield
148
+ end
149
+
150
+ self.check_log_rotation!
151
+
152
+ @log.write(@formatter.call(level, @time_source.now, program, message))
153
+ end
154
+ end
155
+
156
+ def close
157
+ return unless (@log)
158
+
159
+ @log.close
160
+ @log = nil
161
+ end
162
+
163
+ def opened?
164
+ !!@log
165
+ end
166
+
167
+ def closed?
168
+ !@log
169
+ end
170
+
171
+ def create_time
172
+ @log and @log.ctime
173
+ end
174
+
175
+ def size
176
+ @log and @log.size
177
+ end
178
+
179
+ def age(relative_to = nil)
180
+ (relative_to || @time_source.now) - @log.ctime
181
+ end
182
+
183
+ protected
184
+ def next_rotation_time
185
+ case (@period)
186
+ when Fixnum, Float
187
+ @time_source.now + @period
188
+ when :daily
189
+ Birling::Support.next_day(@time_source.now)
190
+ when :hourly
191
+ Birling::Support.next_hour(@time_source.now)
192
+ else
193
+ nil
194
+ end
195
+ end
196
+
197
+ def prune_logs!
198
+ return unless (@path and (@retain_period or @retain_count))
199
+
200
+ log_spec = @path.sub(/\.(\w+)$/, '*')
201
+
202
+ logs = (Dir.glob(log_spec) - [ @path ]).collect do |p|
203
+ stat = File.stat(p)
204
+ create_time = (stat and stat.ctime or @time_source.now)
205
+
206
+ [ p, create_time ]
207
+ end.sort_by do |r|
208
+ r[1] || @time_source.now
209
+ end
210
+
211
+ if (@retain_period)
212
+ logs.reject! do |r|
213
+ if (Time.now - r[1] > @retain_period)
214
+ FileUtils.rm_f(r[0])
215
+ end
216
+ end
217
+ end
218
+
219
+ if (@retain_count)
220
+ # The logs array is sorted from oldest to newest, so retaining the N
221
+ # newest entries entails stripping them off the end with pop.
222
+
223
+ logs.pop(@retain_count)
224
+
225
+ FileUtils.rm_f(logs.collect { |r| r[0] })
226
+ end
227
+ end
228
+
229
+ def check_log_rotation!
230
+ return unless (@rotation_time)
231
+
232
+ if (@time_source.now >= @rotation_time)
233
+ self.log_open!
234
+
235
+ @rotation_time = self.next_rotation_time
236
+ end
237
+ end
238
+
239
+ def log_open!
240
+ if (@path_format)
241
+ @current_path = @time_source.now.strftime(@path_format)
242
+
243
+ @log = File.open(@current_path, 'a')
244
+
245
+ if (File.exist?(@path) and File.symlink?(@path))
246
+ File.unlink(@path)
247
+ File.symlink(@path, @current_path)
248
+ end
249
+
250
+ self.prune_logs!
251
+ else
252
+ @current_path = @path
253
+
254
+ @log = File.open(@current_path, 'a')
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,20 @@
1
+ module Birling::Support
2
+ def next_day(time, time_source = nil)
3
+ (time_source || Time).local(
4
+ time.year,
5
+ time.month,
6
+ time.day,
7
+ 23,
8
+ 59,
9
+ 59
10
+ ) + 1
11
+ end
12
+
13
+ def next_hour(time, time_source = nil)
14
+ seconds_left = time.to_i % 3600
15
+
16
+ time + (seconds_left > 0 ? seconds_left : 3600)
17
+ end
18
+
19
+ extend self
20
+ end
data/lib/birling.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Birling
2
+ # == Submodules ===========================================================
3
+
4
+ autoload(:Formatter, 'birling/formatter')
5
+ autoload(:Logger, 'birling/logger')
6
+ autoload(:Support, 'birling/support')
7
+
8
+ # == Module Methods =======================================================
9
+
10
+ def self.open(path, options = nil)
11
+ Birling::Logger.new(path, options)
12
+ end
13
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'fileutils'
13
+ require 'test/unit'
14
+
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
17
+
18
+ require 'birling'
19
+
20
+ class Time::Warped < Time
21
+ def self.now
22
+ @now || super
23
+ end
24
+
25
+ def self.now=(value)
26
+ @now = value
27
+ end
28
+ end
29
+
30
+ class Test::Unit::TestCase
31
+ def in_time_zone(zone)
32
+ tz = ENV['TZ']
33
+
34
+ ENV['tz'] = zone
35
+
36
+ yield if (block_given?)
37
+
38
+ ensure
39
+ ENV['tz'] = tz
40
+ end
41
+
42
+ def temp_path(name = nil)
43
+ name ||= begin
44
+ @temp_path_inc ||= 0
45
+
46
+ _name = '%05d.%05d.tmp' % [ @temp_path_inc, $$ ]
47
+ @temp_path_inc += 1
48
+
49
+ _name
50
+ end
51
+
52
+ case (name)
53
+ when Symbol
54
+ name = "#{name}.log"
55
+ end
56
+
57
+ @temp_path ||= File.expand_path('../tmp', File.dirname(__FILE__))
58
+
59
+ full_path = File.expand_path(name, @temp_path)
60
+
61
+ FileUtils::mkdir_p(File.dirname(full_path))
62
+
63
+ if (block_given?)
64
+ begin
65
+ yield(full_path)
66
+ ensure
67
+ remove_spec = File.expand_path('*', @temp_path)
68
+
69
+ FileUtils.rm_f(Dir.glob(remove_spec))
70
+ end
71
+ end
72
+
73
+ full_path
74
+ end
75
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestBirling < Test::Unit::TestCase
4
+ def test_module
5
+ assert Birling
6
+ end
7
+
8
+ def test_open
9
+ _path = nil
10
+
11
+ temp_path do |path|
12
+ _path = path
13
+ log = Birling.open(path)
14
+
15
+ assert_equal Birling::Logger, log.class
16
+
17
+ assert log
18
+ assert File.exist?(path)
19
+
20
+ assert log.opened?
21
+ assert !log.closed?
22
+ assert_equal 0, log.size
23
+
24
+ assert log.debug?
25
+
26
+ log.debug("Test")
27
+
28
+ assert log.size > 0
29
+
30
+ log.close
31
+
32
+ assert !log.opened?
33
+ assert log.closed?
34
+ end
35
+
36
+ assert !File.exist?(_path)
37
+ end
38
+
39
+ def test_time_warped
40
+ _now = Time.now
41
+
42
+ Time::Warped.now = _now
43
+
44
+ assert_not_equal Time.now, Time.now
45
+ assert_equal _now, Time::Warped.now
46
+
47
+ Time::Warped.now = nil
48
+
49
+ assert_not_equal _now, Time::Warped.now
50
+ end
51
+ end
@@ -0,0 +1,203 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestBirlingLogger < Test::Unit::TestCase
4
+ def test_defaults
5
+ temp_path do |path|
6
+ log = Birling::Logger.new(path)
7
+
8
+ assert log
9
+
10
+ assert log.opened?
11
+ assert !log.closed?
12
+ assert_equal 0, log.size
13
+ assert Time.now >= log.create_time
14
+
15
+ assert_equal Birling::Formatter, log.formatter
16
+ assert_equal Time, log.time_source
17
+ assert_equal nil, log.period
18
+ end
19
+ end
20
+
21
+ def test_with_handle
22
+ s = StringIO.new
23
+
24
+ log = Birling::Logger.new(s)
25
+
26
+ assert log.opened?
27
+
28
+ assert_equal 0, log.size
29
+ end
30
+
31
+ def test_formatter
32
+ formatter_called = false
33
+ formatter = lambda do |severity, time, program, message|
34
+ formatter_called = true
35
+ message
36
+ end
37
+
38
+ output = StringIO.new
39
+ log = Birling::Logger.new(output, :formatter => formatter)
40
+
41
+ log.debug("Test")
42
+
43
+ assert_equal true, formatter_called
44
+
45
+ output.rewind
46
+ assert_equal "Test", output.read
47
+ end
48
+
49
+ def test_default_level
50
+ temp_path do |path|
51
+ log = Birling::Logger.new(path)
52
+
53
+ assert log
54
+
55
+ assert log.opened?
56
+ assert !log.closed?
57
+ assert_equal 0, log.size
58
+
59
+ assert log.debug?
60
+
61
+ log.debug("Test")
62
+
63
+ current_size = log.size
64
+ assert current_size > 0
65
+ end
66
+ end
67
+
68
+ def test_direct_write
69
+ output = StringIO.new
70
+
71
+ log = Birling::Logger.new(output)
72
+
73
+ log << "TEST"
74
+
75
+ output.rewind
76
+ assert_equal "TEST", output.read
77
+ end
78
+
79
+ def test_level_filter
80
+ output = StringIO.new
81
+
82
+ log = Birling::Logger.new(
83
+ output,
84
+ :formatter => lambda { |s, t, p, m| "#{m}\n" },
85
+ :severity => :info
86
+ )
87
+
88
+ log.debug("DEBUG")
89
+ log.info("INFO")
90
+
91
+ output.rewind
92
+ assert_equal "INFO\n", output.read
93
+ end
94
+
95
+ def test_reopen
96
+ temp_path do |path|
97
+ log = Birling::Logger.new(path)
98
+
99
+ assert log.debug?
100
+
101
+ log.debug("Test")
102
+
103
+ current_size = log.size
104
+ assert current_size > 0
105
+
106
+ create_time = log.create_time
107
+ assert create_time <= Time.now
108
+
109
+ log.close
110
+
111
+ log = Birling::Logger.new(path)
112
+
113
+ assert_equal current_size, log.size
114
+ assert_equal create_time, log.create_time
115
+ end
116
+ end
117
+
118
+ def test_time_source
119
+ temp_path do |path|
120
+ frozen_time = Time.now
121
+ Time::Warped.now = frozen_time
122
+
123
+ logger = Birling::Logger.new(path, :time_source => Time::Warped)
124
+
125
+ assert_equal frozen_time, logger.time_source.now
126
+ end
127
+ end
128
+
129
+ def test_cycling
130
+ temp_path(:cycle) do |path|
131
+ start = Time.now
132
+ Time::Warped.now = start
133
+ logger = Birling::Logger.new(path, :period => 1, :time_source => Time::Warped)
134
+
135
+ assert_equal 1, logger.period
136
+
137
+ current_path = logger.current_path
138
+ assert_equal '%s', logger.path_time_format
139
+
140
+ logger.debug("Test")
141
+
142
+ Time::Warped.now += 1
143
+
144
+ logger.debug("Test")
145
+
146
+ assert_not_equal current_path, logger.current_path
147
+
148
+ current_path = logger.current_path
149
+
150
+ Time::Warped.now += 1
151
+
152
+ logger.debug("Test")
153
+
154
+ assert_not_equal current_path, logger.current_path
155
+ end
156
+ end
157
+
158
+ def test_retain_count
159
+ temp_path(:cycle) do |path|
160
+ start = Time.now
161
+ Time::Warped.now = start
162
+
163
+ retain_count = 10
164
+
165
+ logger = Birling::Logger.new(
166
+ path,
167
+ :period => 1,
168
+ :time_source => Time::Warped,
169
+ :retain_count => retain_count
170
+ )
171
+
172
+ (retain_count + 5).times do |n|
173
+ logger.debug("Test")
174
+ Time::Warped.now += 1
175
+ logger.debug("Test")
176
+ end
177
+
178
+ assert_equal retain_count, Dir.glob(logger.path_format % '*').length
179
+ end
180
+ end
181
+
182
+ def test_retain_period
183
+ temp_path(:cycle) do |path|
184
+ retain_period = 3
185
+
186
+ logger = Birling::Logger.new(
187
+ path,
188
+ :period => 1,
189
+ :retain_period => retain_period
190
+ )
191
+
192
+ finish = Time.now + retain_period + 5
193
+
194
+ while (Time.now < finish)
195
+ logger.debug("Test")
196
+ Time::Warped.now += 1
197
+ logger.debug("Test")
198
+ end
199
+
200
+ assert_equal retain_period + 1, Dir.glob(logger.path_format % '*').length
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestBirlingSupport < Test::Unit::TestCase
4
+ def test_next_day_on_dst_flip
5
+ in_time_zone('EST5EDT') do
6
+ time = Time.new(2012, 11, 4)
7
+
8
+ assert_equal time.day, (time + 86400).day
9
+
10
+ next_day = Birling::Support.next_day(time)
11
+
12
+ assert_equal 2012, next_day.year
13
+ assert_equal 11, next_day.month
14
+ assert_equal 5, next_day.day
15
+ assert_equal 0, next_day.hour
16
+ assert_equal 0, next_day.min
17
+ assert_equal 0, next_day.sec
18
+ end
19
+ end
20
+
21
+ def test_hour_day_on_dst_flip
22
+ in_time_zone('EST5EDT') do
23
+ time = Time.new(2012, 11, 4, 0, 59, 59) + 1
24
+
25
+ assert_equal time.hour, (time + 3600).hour
26
+
27
+ next_hour = Birling::Support.next_hour(time)
28
+
29
+ assert_equal 2012, next_hour.year
30
+ assert_equal 11, next_hour.month
31
+ assert_equal 4, next_hour.day
32
+ assert_equal 1, next_hour.hour
33
+ assert_equal 0, next_hour.min
34
+ assert_equal 0, next_hour.sec
35
+
36
+ assert_equal 3600, next_hour - time
37
+ end
38
+ end
39
+
40
+ def test_next_day_at_year_end
41
+ in_time_zone('EST5EDT') do
42
+ time = Time.new(2012, 12, 31)
43
+
44
+ next_day = Birling::Support.next_day(time)
45
+
46
+ assert_equal 2013, next_day.year
47
+ assert_equal 1, next_day.month
48
+ assert_equal 1, next_day.day
49
+ assert_equal 0, next_day.hour
50
+ assert_equal 0, next_day.min
51
+ assert_equal 0, next_day.sec
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: birling
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Scott Tadman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: jeweler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Mostly drop-in replacement for Logger with a more robust log rotation
47
+ facility
48
+ email: github@tadman.ca
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files:
52
+ - LICENSE.txt
53
+ - README.md
54
+ files:
55
+ - .document
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - VERSION
61
+ - lib/birling.rb
62
+ - lib/birling/formatter.rb
63
+ - lib/birling/log.rb
64
+ - lib/birling/logger.rb
65
+ - lib/birling/support.rb
66
+ - test/helper.rb
67
+ - test/test_birling.rb
68
+ - test/test_birling_logger.rb
69
+ - test/test_birling_support.rb
70
+ homepage: http://github.com/twg/birling
71
+ licenses:
72
+ - MIT
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.24
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Logger with simple log rotation system
95
+ test_files: []