sawmill 0.0.1

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.
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