sawmill 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/History.rdoc +3 -0
  2. data/README.rdoc +81 -0
  3. data/Rakefile +147 -0
  4. data/lib/sawmill/entry.rb +307 -0
  5. data/lib/sawmill/entry_classifier.rb +75 -0
  6. data/lib/sawmill/entry_processor/build_records.rb +157 -0
  7. data/lib/sawmill/entry_processor/conditionals.rb +444 -0
  8. data/lib/sawmill/entry_processor/filter_basic_fields.rb +145 -0
  9. data/lib/sawmill/entry_processor/format.rb +228 -0
  10. data/lib/sawmill/entry_processor/simple_queue.rb +116 -0
  11. data/lib/sawmill/entry_processor.rb +158 -0
  12. data/lib/sawmill/errors.rb +66 -0
  13. data/lib/sawmill/level.rb +264 -0
  14. data/lib/sawmill/log_record_middleware.rb +93 -0
  15. data/lib/sawmill/logger.rb +373 -0
  16. data/lib/sawmill/parser.rb +181 -0
  17. data/lib/sawmill/record.rb +255 -0
  18. data/lib/sawmill/record_processor/conditionals.rb +330 -0
  19. data/lib/sawmill/record_processor/decompose.rb +75 -0
  20. data/lib/sawmill/record_processor/filter_by_attributes.rb +87 -0
  21. data/lib/sawmill/record_processor/filter_by_record_id.rb +77 -0
  22. data/lib/sawmill/record_processor/format.rb +88 -0
  23. data/lib/sawmill/record_processor/simple_queue.rb +117 -0
  24. data/lib/sawmill/record_processor.rb +137 -0
  25. data/lib/sawmill/rotater/base.rb +90 -0
  26. data/lib/sawmill/rotater/date_based_log_file.rb +145 -0
  27. data/lib/sawmill/rotater/shifting_log_file.rb +166 -0
  28. data/lib/sawmill/rotater.rb +236 -0
  29. data/lib/sawmill/util/queue.rb +138 -0
  30. data/lib/sawmill/version.rb +47 -0
  31. data/lib/sawmill.rb +78 -0
  32. data/tests/tc_entry_processors.rb +138 -0
  33. data/tests/tc_formatter_parser.rb +144 -0
  34. data/tests/tc_levels.rb +118 -0
  35. data/tests/tc_logger.rb +315 -0
  36. data/tests/tc_record_processors.rb +117 -0
  37. data/tests/tc_records.rb +206 -0
  38. metadata +116 -0
@@ -0,0 +1,145 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill formatter utility
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+ class Rotater
40
+
41
+
42
+ # A rotation strategy that produces log files with the date stamp in the
43
+ # file name. For example, you could set up an hourly log rotation that
44
+ # produces the following files:
45
+ #
46
+ # rails.2009-10-09-22.log
47
+ # rails.2009-10-09-23.log
48
+ # rails.2009-10-10-00.log
49
+ # rails.2009-10-10-01.log
50
+ # etc...
51
+ #
52
+ # The exact format depends on the rotation frequency, which could be
53
+ # anywhere from yearly to hourly. For settings less frequent than
54
+ # hourly, fewer fields will appear in the date stamp portion of the
55
+ # file name.
56
+
57
+ class DateBasedLogFile
58
+
59
+
60
+ # Create a new date-based log file rotation strategy.
61
+ #
62
+ # Recognized options include:
63
+ #
64
+ # <tt>:turnover_frequency</tt>::
65
+ # How often the log files should turn over. Allowed values are:
66
+ # <tt>:yearly</tt>, <tt>:monthly</tt>, <tt>:daily</tt>,
67
+ # <tt>:hourly</tt>, and <tt>:never</tt>.
68
+ # <tt>:dirname</tt>::
69
+ # The directory for the logfiles to be output.
70
+ # If not specified, the current working directory is used.
71
+ # <tt>:prefix</tt>::
72
+ # The logfile name prefix.
73
+ # In the filename "rails.2009-10-11.log", the prefix is "rails".
74
+ # If not specified, defaults to "sawmill".
75
+ # <tt>:suffix</tt>::
76
+ # The logfile name prefix.
77
+ # In the filename "rails.2009-10-11.log", the suffix is ".log".
78
+ # If not specified, defaults to ".log".
79
+ # <tt>:local_timezone</tt>::
80
+ # If true, use the local timezone to create datestamps.
81
+ # The default is to use UTC.
82
+
83
+ def initialize(options_)
84
+ @turnover_frequency = options_[:turnover_frequency] || :none
85
+ dirname_ = options_[:dirname] || Dir.getwd
86
+ @prefix = File.join(dirname_, options_[:prefix] || 'sawmill')
87
+ @suffix = options_[:suffix] || '.log'
88
+ @local_timezone = options_[:local_timezone]
89
+ @date_pattern =
90
+ case @turnover_frequency
91
+ when :yearly then "%Y"
92
+ when :monthly then "%Y-%m"
93
+ when :daily then "%Y-%m-%d"
94
+ when :hourly then "%Y-%m-%d-%H"
95
+ else nil
96
+ end
97
+ end
98
+
99
+
100
+ # Implements the rotation strategy contract.
101
+
102
+ def preferred_handle
103
+ if @date_pattern
104
+ time_ = Time.now
105
+ time_.utc unless @local_timezone
106
+ time_.strftime(@date_pattern)
107
+ else
108
+ ''
109
+ end
110
+ end
111
+
112
+
113
+ # Implements the rotation strategy contract.
114
+
115
+ def open_handle(handle_)
116
+ if @date_pattern
117
+ path_ = "#{@prefix}.#{handle_}#{@suffix}"
118
+ else
119
+ path_ = @prefix+@suffix
120
+ end
121
+ file_ = File.open(path_, File::CREAT | File::WRONLY | File::APPEND)
122
+ file_.sync = true
123
+ file_
124
+ end
125
+
126
+
127
+ # Implements the rotation strategy contract.
128
+
129
+ def close_handle(handle_, io_)
130
+ io_.close
131
+ end
132
+
133
+
134
+ # Implements the rotation strategy contract.
135
+
136
+ def before_write
137
+ end
138
+
139
+
140
+ end
141
+
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,166 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill formatter utility
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+ class Rotater
40
+
41
+
42
+ # A rotation strategy that "shifts" log files by appending index numbers
43
+ # to the filename when the file reaches a certain size or age. So when
44
+ # the file "foo.log" is ready to rotate, it is renamed "foo.log.0", and
45
+ # a new "foo.log" is started. When that one is ready to rotate, the
46
+ # oldest "foo.log.0" is shifted down to "foo.log.1", "foo.log" is
47
+ # renamed to "foo.log.0", and a new "foo.log" is started. So the oldest
48
+ # logfile is always the one with the largest number suffix, and the
49
+ # file currently being written to has no suffix.
50
+ # This is a common rotation strategy for many unix tools.
51
+
52
+ class ShiftingLogFile
53
+
54
+
55
+ # Create a new shifting log file rotation strategy.
56
+ #
57
+ # Recognized options include:
58
+ #
59
+ # <tt>:dirname</tt>::
60
+ # The directory for the logfiles to be output.
61
+ # If not specified, the current working directory is used.
62
+ # <tt>:filename</tt>::
63
+ # The logfile name.
64
+ # If not specified, defaults to "sawmill.log".
65
+ # <tt>:max_logfile_size</tt>::
66
+ # A logfile will try to rotate once it has reached this size in
67
+ # bytes. If not specified, the file size is not checked.
68
+ # <tt>:shift_period</tt>::
69
+ # A logfile will try to rotate once it has been in service for
70
+ # this many seconds. This parameter also recognizes the values
71
+ # <tt>:yearly</tt>, <tt>:monthly</tt>, <tt>:daily</tt>,
72
+ # and <tt>:hourly</tt>. If not specified, the file's age is
73
+ # not checked.
74
+ # <tt>:history_size</tt>::
75
+ # The maximum number of old logfiles (files with indexes) to
76
+ # keep. Files beyond this history size will be automatically
77
+ # deleted. Default is 1. This value must be at least 1.
78
+
79
+ def initialize(options_)
80
+ @max_logfile_size = options_[:max_logfile_size]
81
+ @shift_period = options_[:shift_period]
82
+ case @shift_period
83
+ when :yearly
84
+ @shift_period = 60*60*24*365
85
+ when :monthly
86
+ @shift_period = 60*60*24*30
87
+ when :daily
88
+ @shift_period = 60*60*24
89
+ when :hourly
90
+ @shift_period = 60*60
91
+ end
92
+ @history_size = options_[:history_size].to_i
93
+ @history_size = 1 if @history_size < 1 && (@max_logfile_size || @shift_period)
94
+ dirname_ = options_[:dirname] || Dir.getwd
95
+ @normal_path = File.join(dirname_, options_[:filename] || 'sawmill.log')
96
+ @preferred_handle = 0
97
+ @open_handles = {}
98
+ @last_shift = Time.now
99
+ end
100
+
101
+
102
+ # Implements the rotation strategy contract.
103
+
104
+ def preferred_handle
105
+ @preferred_handle
106
+ end
107
+
108
+
109
+ # Implements the rotation strategy contract.
110
+
111
+ def open_handle(handle_)
112
+ if handle_ == @preferred_handle
113
+ path_ = @normal_path
114
+ else
115
+ path_ = "#{@normal_path}.#{@preferred_handle-handle_-1}"
116
+ end
117
+ file_ = File.open(path_, File::CREAT | File::WRONLY | File::APPEND)
118
+ file_.sync = true
119
+ @open_handles[handle_] = true
120
+ file_
121
+ end
122
+
123
+
124
+ # Implements the rotation strategy contract.
125
+
126
+ def close_handle(handle_, io_)
127
+ io_.close
128
+ if @preferred_handle - handle_ > @history_size
129
+ File.delete("#{@normal_path}.#{@preferred_handle-handle_-1}") rescue nil
130
+ end
131
+ @open_handles.delete(handle_)
132
+ nil
133
+ end
134
+
135
+
136
+ # Implements the rotation strategy contract.
137
+
138
+ def before_write
139
+ return unless @max_logfile_size || @shift_period
140
+ turnover_ = false
141
+ if @max_logfile_size && File.file?(@normal_path) && File.size(@normal_path) > @max_logfile_size
142
+ turnover_ = true
143
+ end
144
+ if @shift_period && (Time.now - @last_shift) > @shift_period
145
+ turnover_ = true
146
+ end
147
+ if turnover_
148
+ max_ = @preferred_handle - @open_handles.keys.min + 1
149
+ max_ = @history_size if max_ < @history_size
150
+ File.delete("#{@normal_path}.#{max_-1}") rescue nil
151
+ (max_-1).downto(1) do |index_|
152
+ File.rename("#{@normal_path}.#{index_-1}", "#{@normal_path}.#{index_}") rescue nil
153
+ end
154
+ File.rename("#{@normal_path}", "#{@normal_path}.0") rescue nil
155
+ @preferred_handle += 1
156
+ @last_shift = Time.now
157
+ end
158
+ end
159
+
160
+
161
+ end
162
+
163
+
164
+ end
165
+
166
+ end
@@ -0,0 +1,236 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill log rotation utility
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ require 'thread'
38
+
39
+
40
+ module Sawmill
41
+
42
+
43
+ # The Sawmill Rotater provides log rotation services for logfile
44
+ # formatting, supporting several different log rotation strategies.
45
+ #
46
+ # The formatter implemented by Sawmill::EntryProcessor::Format already
47
+ # recognizes a Rotater as a supported destination, and automatically
48
+ # interfaces with it to ensure that log records aren't split into
49
+ # multiple files by rotation.
50
+ #
51
+ # You may also interface with a rotater manually. The core of rotater
52
+ # usage is the Channel, which lets you ensure that groups of log
53
+ # entries end up in the same log file regardless of log rotation.
54
+ # Generally, to use a rotater, you obtain one or more channels and
55
+ # write formatted entries to them, either telling them explicitly
56
+ # where the allowable file breaks are, or by letting the rotater
57
+ # break the file anywhere it wants. See the create_channel method
58
+ # and the Channel object for more details.
59
+
60
+ class Rotater
61
+
62
+
63
+ # Create a rotater using the given rotation strategy.
64
+ # See Sawmill::Rotater::DateBasedLogFile and
65
+ # Sawmill::Rotater::ShiftingLogFile for examples of common strategies.
66
+ #
67
+ # The rotation strategy can be passed as an object or as a class with a
68
+ # set of options that will be used to instantiate the strategy.
69
+ # In addition to those options, the following options are recognized:
70
+ #
71
+ # <tt>:omit_directives</tt>::
72
+ # If true, omit standard logfile directives. Default is false.
73
+
74
+ def initialize(io_manager_, opts_={})
75
+ @omit_directives = opts_.delete(:omit_directives)
76
+ if io_manager_.kind_of?(Class)
77
+ @io_manager = io_manager_.new(opts_)
78
+ else
79
+ @io_manager = io_manager_
80
+ end
81
+ @handles ||= {}
82
+ @mutex ||= Monitor.new
83
+ end
84
+
85
+
86
+ # Create a new Channel for this Rotater. See Sawmill::Rotater::Channel
87
+ # for details on the Channel object.
88
+ #
89
+ # The following options are recognized:
90
+ #
91
+ # <tt>:auto_rotate</tt>::
92
+ # Put the channel in auto-rotate mode. In this mode, the rotater is
93
+ # allowed to rotate the logfile at any time for that channel. It is
94
+ # the equivalent of calling check_rotate on the channel after every
95
+ # write. Default is false.
96
+
97
+ def create_channel(opts_={})
98
+ Channel.new(self, opts_)
99
+ end
100
+
101
+
102
+ def _obtain_handle # :nodoc:
103
+ handle_ = @io_manager.preferred_handle
104
+ if @handles.include?(handle_)
105
+ @handles[handle_][2] += 1
106
+ else
107
+ io_ = @io_manager.open_handle(handle_)
108
+ unless @omit_directives
109
+ io_.write("# sawmill_format: version=1\n")
110
+ end
111
+ @handles[handle_] = [handle_, io_, 1]
112
+ end
113
+ handle_
114
+ end
115
+
116
+
117
+ def _release_handle(handle_) # :nodoc:
118
+ info_ = @handles[handle_]
119
+ info_[2] -= 1
120
+ if info_[2] == 0
121
+ @io_manager.close_handle(handle_, info_[1])
122
+ @handles.delete(handle_)
123
+ end
124
+ nil
125
+ end
126
+
127
+
128
+ def _check_rotate_handle(handle_) # :nodoc:
129
+ if handle_ != @io_manager.preferred_handle
130
+ _release_handle(handle_)
131
+ _obtain_handle
132
+ else
133
+ handle_
134
+ end
135
+ end
136
+
137
+
138
+ def _do_open # :nodoc:
139
+ @mutex.synchronize do
140
+ _obtain_handle
141
+ end
142
+ end
143
+
144
+
145
+ def _do_write(handle_, str_, auto_rotate_) # :nodoc:
146
+ @mutex.synchronize do
147
+ @io_manager.before_write
148
+ if auto_rotate_
149
+ handle_ = _check_rotate_handle(handle_)
150
+ end
151
+ info_ = @handles[handle_]
152
+ info_[1].write(str_)
153
+ handle_
154
+ end
155
+ end
156
+
157
+
158
+ def _do_close(handle_) # :nodoc:
159
+ @mutex.synchronize do
160
+ _release_handle(handle_)
161
+ end
162
+ end
163
+
164
+
165
+ def _do_check_rotate(handle_) # :nodoc:
166
+ @mutex.synchronize do
167
+ _check_rotate_handle(handle_)
168
+ end
169
+ end
170
+
171
+
172
+ # A channel is a lightweight object that responds to the write and close
173
+ # methods; that is, it is sufficient for Sawmill::Formatter.
174
+ #
175
+ # When a channel is opened, it locks down a path to the logfile and
176
+ # ensures that the logfile will not rotate out from under it; that is,
177
+ # writes to a channel are ensured to end up in the same physical file.
178
+ #
179
+ # You may choose, at intervals, to explicitly tell the channel that it
180
+ # is okay to rotate the logfile now, by calling check_rotate.
181
+ #
182
+ # You must close a channel when you are done with it. Closing a channel
183
+ # does not close the underlying logfile, but instead tells the rotater
184
+ # that you are done with this channel and that the logfile is free to
185
+ # rotate independent of it.
186
+ #
187
+ # You may have any number of channels open at any time, each on a
188
+ # different rotation schedule. Each may possibly be writing to different
189
+ # files in the rotation at any time, but this is all done automatically
190
+ # behind the scenes.
191
+
192
+ class Channel
193
+
194
+ def initialize(rotater_, opts_={}) # :nodoc:
195
+ @rotater = rotater_
196
+ @auto_rotate = opts_[:auto_rotate]
197
+ @io_handle = @rotater._do_open
198
+ end
199
+
200
+
201
+ # Write a string to this channel.
202
+
203
+ def write(str_)
204
+ if @io_handle
205
+ @rotater._do_write(@io_handle, str_, @auto_rotate)
206
+ end
207
+ end
208
+
209
+
210
+ # Close this channel, telling the rotater that this channel no longer
211
+ # needs to constrain the log rotation.
212
+
213
+ def close
214
+ if @io_handle
215
+ @rotater._do_close(@io_handle)
216
+ @io_handle = nil
217
+ end
218
+ end
219
+
220
+
221
+ # Manually tell the rotater that this channel is at a stopping point
222
+ # and that the log file may rotate at this time.
223
+
224
+ def check_rotate
225
+ if @io_handle
226
+ @io_handle = @rotater._do_check_rotate(@io_handle)
227
+ end
228
+ end
229
+
230
+
231
+ end
232
+
233
+
234
+ end
235
+
236
+ end
@@ -0,0 +1,138 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill entry stream processor interface
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2009 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Sawmill
38
+
39
+ module Util
40
+
41
+
42
+ # A simple queue that optionally provides an upper size limit.
43
+
44
+ class Queue
45
+
46
+
47
+ # Recognized options include:
48
+ #
49
+ # <tt>:limit</tt>::
50
+ # Size limit for the queue. If not specified, the queue can grow
51
+ # arbitrarily large.
52
+ # <tt>:drop_oldest</tt>::
53
+ # If set to true, then when an item is added to a full queue, the
54
+ # oldest item is dropped. If set to false or not specified, then
55
+ # the new item is not added.
56
+
57
+ def initialize(opts_={})
58
+ limit_ = opts_[:limit]
59
+ @buffer = limit_ ? ::Array.new(limit_) : []
60
+ @push_ptr = limit_ ? 0 : nil
61
+ @pop_ptr = nil
62
+ @drop_oldest = limit_ && opts_[:drop_oldest]
63
+ end
64
+
65
+
66
+ # Attempt to push an item on the queue.
67
+ #
68
+ # If the queue is full, then the behavior is determined by the
69
+ # :drop_oldest setting provided to the constructor.
70
+ #
71
+ # Returns true if the object was pushed on the queue, or false if the
72
+ # queue was full.
73
+
74
+ def enqueue(object_)
75
+ result_ = true
76
+ if @push_ptr
77
+ if @pop_ptr == @push_ptr
78
+ if @drop_oldest
79
+ @pop_ptr += 1
80
+ @pop_ptr = 0 if @pop_ptr == @buffer.size
81
+ result_ = false
82
+ else
83
+ return false
84
+ end
85
+ elsif @pop_ptr.nil?
86
+ @pop_ptr = @push_ptr
87
+ end
88
+ @buffer[@push_ptr] = object_
89
+ @push_ptr += 1
90
+ @push_ptr = 0 if @push_ptr == @buffer.size
91
+ else
92
+ @buffer.push(object_)
93
+ end
94
+ result_
95
+ end
96
+
97
+
98
+ # Return the oldest item in the queue, or nil if the queue is empty.
99
+
100
+ def dequeue
101
+ if @push_ptr
102
+ if @pop_ptr
103
+ object_ = @buffer[@pop_ptr]
104
+ @pop_ptr += 1
105
+ @pop_ptr = 0 if @pop_ptr == @buffer.size
106
+ @pop_ptr = nil if @pop_ptr == @push_ptr
107
+ object_
108
+ else
109
+ nil
110
+ end
111
+ else
112
+ @buffer.shift
113
+ end
114
+ end
115
+
116
+
117
+ # Return the size of the queue, which is 0 if the queue is empty.
118
+
119
+ def size
120
+ if @push_ptr
121
+ if @pop_ptr
122
+ value_ = @push_ptr - @pop_ptr
123
+ value_ > 0 ? value_ : value_ + @buffer.size
124
+ else
125
+ 0
126
+ end
127
+ else
128
+ @buffer.size
129
+ end
130
+ end
131
+
132
+
133
+ end
134
+
135
+
136
+ end
137
+
138
+ end