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.
- data/History.rdoc +3 -0
- data/README.rdoc +81 -0
- data/Rakefile +147 -0
- data/lib/sawmill/entry.rb +307 -0
- data/lib/sawmill/entry_classifier.rb +75 -0
- data/lib/sawmill/entry_processor/build_records.rb +157 -0
- data/lib/sawmill/entry_processor/conditionals.rb +444 -0
- data/lib/sawmill/entry_processor/filter_basic_fields.rb +145 -0
- data/lib/sawmill/entry_processor/format.rb +228 -0
- data/lib/sawmill/entry_processor/simple_queue.rb +116 -0
- data/lib/sawmill/entry_processor.rb +158 -0
- data/lib/sawmill/errors.rb +66 -0
- data/lib/sawmill/level.rb +264 -0
- data/lib/sawmill/log_record_middleware.rb +93 -0
- data/lib/sawmill/logger.rb +373 -0
- data/lib/sawmill/parser.rb +181 -0
- data/lib/sawmill/record.rb +255 -0
- data/lib/sawmill/record_processor/conditionals.rb +330 -0
- data/lib/sawmill/record_processor/decompose.rb +75 -0
- data/lib/sawmill/record_processor/filter_by_attributes.rb +87 -0
- data/lib/sawmill/record_processor/filter_by_record_id.rb +77 -0
- data/lib/sawmill/record_processor/format.rb +88 -0
- data/lib/sawmill/record_processor/simple_queue.rb +117 -0
- data/lib/sawmill/record_processor.rb +137 -0
- data/lib/sawmill/rotater/base.rb +90 -0
- data/lib/sawmill/rotater/date_based_log_file.rb +145 -0
- data/lib/sawmill/rotater/shifting_log_file.rb +166 -0
- data/lib/sawmill/rotater.rb +236 -0
- data/lib/sawmill/util/queue.rb +138 -0
- data/lib/sawmill/version.rb +47 -0
- data/lib/sawmill.rb +78 -0
- data/tests/tc_entry_processors.rb +138 -0
- data/tests/tc_formatter_parser.rb +144 -0
- data/tests/tc_levels.rb +118 -0
- data/tests/tc_logger.rb +315 -0
- data/tests/tc_record_processors.rb +117 -0
- data/tests/tc_records.rb +206 -0
- metadata +116 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill entry processor that checks for entry field values.
|
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 EntryProcessor
|
40
|
+
|
41
|
+
|
42
|
+
# A basic filter that knows how to check level and progname.
|
43
|
+
#
|
44
|
+
# This is a boolean processor, so it merely returns true or false based
|
45
|
+
# on the filter result. Use this in conjunction with an If processor to
|
46
|
+
# actually perform other actions based on the result.
|
47
|
+
|
48
|
+
class FilterBasicFields < Base
|
49
|
+
|
50
|
+
|
51
|
+
# Create a new filter.
|
52
|
+
#
|
53
|
+
# Recognized options include:
|
54
|
+
#
|
55
|
+
# <tt>:level</tt>::
|
56
|
+
# Lowest level that will be accepted. This should be either a
|
57
|
+
# Sawmill::Level object or an integer value or string/symbol that
|
58
|
+
# represents a level. If set to nil or not specified, this filter
|
59
|
+
# does not check the level.
|
60
|
+
# <tt>:progname</tt>::
|
61
|
+
# Progname filter. This can be either a string or a Regexp. If set
|
62
|
+
# to nil or not specified, this filter does not check the progname.
|
63
|
+
# <tt>:accept_record_delimiters</tt>::
|
64
|
+
# If set to true, accepts all begin_record and end_record entries
|
65
|
+
# regardless of the level or progname. If set to false, accepts no
|
66
|
+
# such entries. Otherwise, if not specified, those entries are
|
67
|
+
# subject to the usual level and progname filters.
|
68
|
+
# <tt>:accept_attributes</tt>::
|
69
|
+
# If set to true, accepts all attribute and multi_attribute entries
|
70
|
+
# regardless of the level or progname. If set to false, accepts no
|
71
|
+
# such entries. Otherwise, if not specified, those entries are
|
72
|
+
# subject to the usual level and progname filters.
|
73
|
+
# <tt>:accept_incomparable_levels</tt>::
|
74
|
+
# If set to true, accepts entries whose level is not comparable to
|
75
|
+
# the given <tt>:level</tt> setting. Otherwise, rejects all such
|
76
|
+
# entries.
|
77
|
+
# <tt>:accept_unknown</tt>::
|
78
|
+
# If set to true, accepts all entries of type :unknown_data.
|
79
|
+
# Otherwise, rejects all such entries.
|
80
|
+
|
81
|
+
def initialize(opts_={})
|
82
|
+
@level = opts_[:level]
|
83
|
+
@progname = opts_[:progname]
|
84
|
+
@accept_record_delimiters = opts_[:accept_record_delimiters]
|
85
|
+
@accept_attributes = opts_[:accept_attributes]
|
86
|
+
@accept_incomparable_levels = opts_[:accept_incomparable_levels]
|
87
|
+
@accept_unknown = opts_[:accept_unknown]
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def begin_record(entry_)
|
92
|
+
@accept_record_delimiters.nil? ? _check_filter(entry_) : @accept_record_delimiters
|
93
|
+
end
|
94
|
+
|
95
|
+
def end_record(entry_)
|
96
|
+
@accept_record_delimiters.nil? ? _check_filter(entry_) : @accept_record_delimiters
|
97
|
+
end
|
98
|
+
|
99
|
+
def message(entry_)
|
100
|
+
_check_filter(entry_)
|
101
|
+
end
|
102
|
+
|
103
|
+
def attribute(entry_)
|
104
|
+
@accept_attributes.nil? ? _check_filter(entry_) : @accept_attributes
|
105
|
+
end
|
106
|
+
|
107
|
+
def unknown_data(entry_)
|
108
|
+
@accept_unknown
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def close
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
|
119
|
+
def _check_filter(entry_) # :nodoc:
|
120
|
+
if @level
|
121
|
+
level_ = entry_.level
|
122
|
+
if @level.kind_of?(::Sawmill::Level)
|
123
|
+
check_level_ = @level
|
124
|
+
if level_.group != check_level_.group
|
125
|
+
return false unless @accept_incomparable_levels
|
126
|
+
end
|
127
|
+
else
|
128
|
+
check_level_ = level_.group.get(@level)
|
129
|
+
unless check_level_
|
130
|
+
return false unless @accept_incomparable_levels
|
131
|
+
end
|
132
|
+
end
|
133
|
+
return false if check_level_ && level_ < check_level_
|
134
|
+
end
|
135
|
+
return false if @progname && entry_.progname != @progname
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill entry processor that formats for log files
|
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 EntryProcessor
|
40
|
+
|
41
|
+
|
42
|
+
# This processor formats log entries and writes them to a destination.
|
43
|
+
|
44
|
+
class Format < Base
|
45
|
+
|
46
|
+
|
47
|
+
# Create a formatter.
|
48
|
+
#
|
49
|
+
# The destination can be a ruby IO object, a Sawmill::Rotater, or any
|
50
|
+
# object that responds to the "write" and "close" methods as defined
|
51
|
+
# by the ruby IO class.
|
52
|
+
#
|
53
|
+
# Recognized options include:
|
54
|
+
#
|
55
|
+
# <tt>:include_id</tt>::
|
56
|
+
# Include the record ID in every log entry. Default is false.
|
57
|
+
# <tt>:fractional_second_digits</tt>::
|
58
|
+
# Number of digits of fractional seconds to display in timestamps.
|
59
|
+
# Default is 2. Accepted values are 0 to 6.
|
60
|
+
# <tt>:level_width</tt>::
|
61
|
+
# Column width of the level field.
|
62
|
+
# <tt>:local_time</tt>::
|
63
|
+
# If true, outputs local time with the timezone offset indicator.
|
64
|
+
# If false (the default), outputs UTC.
|
65
|
+
# <tt>:iso_8601_time</tt>::
|
66
|
+
# If true, outputs time in strict ISO 8601 format.
|
67
|
+
# If false (the default), outputs a slightly more readable format.
|
68
|
+
|
69
|
+
def initialize(destination_, opts_={})
|
70
|
+
if destination_.kind_of?(Rotater)
|
71
|
+
@rotater = destination_
|
72
|
+
@channels = {}
|
73
|
+
@standby_channel = nil
|
74
|
+
elsif destination_.respond_to?(:close) && destination_.respond_to?(:write)
|
75
|
+
@io = destination_
|
76
|
+
else
|
77
|
+
raise ArgumentError, "Unknown destination type"
|
78
|
+
end
|
79
|
+
@include_id = opts_[:include_id]
|
80
|
+
@fractional_second_digits = (opts_[:fractional_second_digits] || 2).to_i
|
81
|
+
@fractional_second_digits = 0 if @fractional_second_digits < 0
|
82
|
+
@fractional_second_digits = 6 if @fractional_second_digits > 6
|
83
|
+
@usec_factor = 1
|
84
|
+
(6 - @fractional_second_digits).times{ @usec_factor *= 10 }
|
85
|
+
@level_width = opts_[:level_width]
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def begin_record(entry_)
|
90
|
+
return false unless @io || @rotater
|
91
|
+
record_id_ = entry_.record_id
|
92
|
+
if @rotater
|
93
|
+
if @standby_channel
|
94
|
+
io_ = @standby_channel
|
95
|
+
@standby_channel = nil
|
96
|
+
else
|
97
|
+
io_ = @rotater.create_channel
|
98
|
+
end
|
99
|
+
@channels[record_id_] = io_
|
100
|
+
else
|
101
|
+
io_ = @io
|
102
|
+
end
|
103
|
+
io_.write(_format_entry(entry_, '^', "BEGIN #{record_id_}"))
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
def end_record(entry_)
|
108
|
+
return false unless @io || @rotater
|
109
|
+
record_id_ = entry_.record_id
|
110
|
+
str_ = _format_entry(entry_, '$', "END #{record_id_}")
|
111
|
+
if @rotater
|
112
|
+
if (channel_ = @channels.delete(record_id_))
|
113
|
+
@standby_channel.close if @standby_channel
|
114
|
+
@standby_channel = channel_
|
115
|
+
else
|
116
|
+
@standby_channel ||= @rotater.create_channel
|
117
|
+
end
|
118
|
+
@standby_channel.write(str_)
|
119
|
+
@standby_channel.check_rotate
|
120
|
+
else
|
121
|
+
@io.write(str_)
|
122
|
+
end
|
123
|
+
true
|
124
|
+
end
|
125
|
+
|
126
|
+
def message(entry_)
|
127
|
+
return false unless @io || @rotater
|
128
|
+
_write_str(_format_entry(entry_, '.', entry_.message), entry_.record_id)
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
def attribute(entry_)
|
133
|
+
return false unless @io || @rotater
|
134
|
+
opcode_ = entry_.operation == :append ? '+' : '='
|
135
|
+
str_ = _format_entry(entry_, '=', "#{entry_.key} #{opcode_} #{entry_.value}")
|
136
|
+
_write_str(str_, entry_.record_id)
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
def unknown_data(entry_)
|
141
|
+
return false unless @io || @rotater
|
142
|
+
_write_str(entry_.line+"\n", entry_.record_id)
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
def close
|
147
|
+
if @rotater
|
148
|
+
@default_channel.close
|
149
|
+
@channels.values.each{ |channel_| channel_.close }
|
150
|
+
@rotater = nil
|
151
|
+
elsif @io
|
152
|
+
@io.close
|
153
|
+
@io = nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def _write_str(str_, record_id_) # :nodoc:
|
160
|
+
if @rotater
|
161
|
+
io_ = @channels[record_id_]
|
162
|
+
if io_
|
163
|
+
io_.write(str_)
|
164
|
+
else
|
165
|
+
@standby_channel ||= @rotater.create_channel
|
166
|
+
@standby_channel.write(str_)
|
167
|
+
@standby_channel.check_rotate
|
168
|
+
end
|
169
|
+
else
|
170
|
+
@io.write(str_)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def _format_entry(entry_, marker_, str_) # :nodoc:
|
175
|
+
id_ = @include_id ? entry_.record_id : nil
|
176
|
+
id_ = id_ ? ' '+id_ : ''
|
177
|
+
time_ = entry_.timestamp.getutc
|
178
|
+
str_ = str_.split("\n", -1).map do |line_|
|
179
|
+
if line_ =~ /(\\+)$/
|
180
|
+
"#{$`}#{$1}#{$1}"
|
181
|
+
else
|
182
|
+
line_
|
183
|
+
end
|
184
|
+
end.join("\\\n")
|
185
|
+
time_ = entry_.timestamp
|
186
|
+
if @local_time
|
187
|
+
time_ = time_.getlocal
|
188
|
+
else
|
189
|
+
time_ = time_.getutc
|
190
|
+
end
|
191
|
+
if @iso_8601_time
|
192
|
+
timestr_ = time_.strftime('%Y-%m-%dT%H:%M:%S')
|
193
|
+
else
|
194
|
+
timestr_ = time_.strftime('%Y-%m-%d %H:%M:%S')
|
195
|
+
end
|
196
|
+
if @fractional_second_digits > 0
|
197
|
+
timestr_ << (".%0#{@fractional_second_digits}d" % (time_.usec / @usec_factor))
|
198
|
+
end
|
199
|
+
if @local_time
|
200
|
+
offset_ = time_.utc_offset
|
201
|
+
neg_ = offset_ < 0
|
202
|
+
offset_ = -offset_ if neg_
|
203
|
+
offsetstr_ = "%s%02d%02d" % [(neg_ ? '-' : '+'), offset_ / 3600, (offset_ % 3600) / 60]
|
204
|
+
if @iso_8601_time
|
205
|
+
timestr_ << offsetstr_
|
206
|
+
else
|
207
|
+
timestr_ << ' ' << offsetstr_
|
208
|
+
end
|
209
|
+
elsif @iso_8601_time
|
210
|
+
timestr_ << 'Z'
|
211
|
+
end
|
212
|
+
levelstr_ = entry_.level.name.to_s
|
213
|
+
levelstr_ = levelstr_.rjust(@level_width) if @level_width
|
214
|
+
"[#{levelstr_} #{timestr_} #{entry_.progname}#{id_} #{marker_}] #{str_}\n"
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
# Sawmill::Formatter is an alternate name for
|
224
|
+
# Sawmill::EntryProcessor::Format
|
225
|
+
Formatter = EntryProcessor::Format
|
226
|
+
|
227
|
+
|
228
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill entry processor that queues entries
|
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
|
+
|
40
|
+
module EntryProcessor
|
41
|
+
|
42
|
+
|
43
|
+
# This processor simply queues up log entries for later use.
|
44
|
+
|
45
|
+
class SimpleQueue < Base
|
46
|
+
|
47
|
+
|
48
|
+
# Create a queue.
|
49
|
+
#
|
50
|
+
# Recognized options include:
|
51
|
+
#
|
52
|
+
# <tt>:limit</tt>::
|
53
|
+
# Size limit for the queue. If not specified, the queue can grow
|
54
|
+
# arbitrarily large.
|
55
|
+
# <tt>:drop_oldest</tt>::
|
56
|
+
# If set to true, then when an item is added to a full queue, the
|
57
|
+
# oldest item is dropped. If set to false or not specified, then
|
58
|
+
# the new item is not added.
|
59
|
+
|
60
|
+
def initialize(opts_={})
|
61
|
+
@queue = Util::Queue.new(opts_)
|
62
|
+
@closed = false
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Return the oldest entry in the queue, or nil if the queue is empty.
|
67
|
+
|
68
|
+
def dequeue
|
69
|
+
@queue.dequeue
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Return the size of the queue, which is 0 if the queue is empty.
|
74
|
+
|
75
|
+
def size
|
76
|
+
@queue.size
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def begin_record(entry_)
|
81
|
+
@queue.enqueue(entry_) unless @closed
|
82
|
+
!@closed
|
83
|
+
end
|
84
|
+
|
85
|
+
def end_record(entry_)
|
86
|
+
@queue.enqueue(entry_) unless @closed
|
87
|
+
!@closed
|
88
|
+
end
|
89
|
+
|
90
|
+
def message(entry_)
|
91
|
+
@queue.enqueue(entry_) unless @closed
|
92
|
+
!@closed
|
93
|
+
end
|
94
|
+
|
95
|
+
def attribute(entry_)
|
96
|
+
@queue.enqueue(entry_) unless @closed
|
97
|
+
!@closed
|
98
|
+
end
|
99
|
+
|
100
|
+
def unknown_data(entry_)
|
101
|
+
@queue.enqueue(entry_) unless @closed
|
102
|
+
!@closed
|
103
|
+
end
|
104
|
+
|
105
|
+
def close
|
106
|
+
@closed = true
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill entry 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
|
+
|
40
|
+
# Entry processors are objects that receive a stream of log entries and
|
41
|
+
# perform some action. Some processors perform their own action, while
|
42
|
+
# others could filter entries and forward them to other processors.
|
43
|
+
#
|
44
|
+
# The API contract for an entry processor is specified by the class
|
45
|
+
# Sawmill::EntryProcessor::Base. Processors could subclass that base
|
46
|
+
# class, or could just duck-type the methods.
|
47
|
+
#
|
48
|
+
# Sawmill's basic entry processor classes live into this module's
|
49
|
+
# namespace, but this is not a requirement for your own processors.
|
50
|
+
|
51
|
+
module EntryProcessor
|
52
|
+
|
53
|
+
|
54
|
+
class Builder # :nodoc:
|
55
|
+
include ::Blockenspiel::DSL
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# A base class for entry processors.
|
60
|
+
#
|
61
|
+
# Entry processors need not necessarily subclass this class, but should
|
62
|
+
# at least duck-type the methods.
|
63
|
+
#
|
64
|
+
# If a class subclasses this class, *and* lives in the EntryProcessor
|
65
|
+
# namespace, then it will automatically be available in the build
|
66
|
+
# interface. See EntryProcessor#build.
|
67
|
+
|
68
|
+
class Base
|
69
|
+
|
70
|
+
|
71
|
+
# Receive and process a Sawmill::Entry::BeginRecord.
|
72
|
+
|
73
|
+
def begin_record(entry_)
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Receive and process a Sawmill::Entry::EndRecord.
|
79
|
+
|
80
|
+
def end_record(entry_)
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# Receive and process a Sawmill::Entry::Message.
|
86
|
+
|
87
|
+
def message(entry_)
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Receive and process a Sawmill::Entry::Attribute.
|
93
|
+
|
94
|
+
def attribute(entry_)
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# Receive and process a Sawmill::Entry::UnknownData.
|
100
|
+
|
101
|
+
def unknown_data(entry_)
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Close down the processor. After this is called, the processor should
|
107
|
+
# ignore any further entries.
|
108
|
+
|
109
|
+
def close
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def self.inherited(subclass_) # :nodoc:
|
114
|
+
if subclass_.name =~ /^Sawmill::EntryProcessor::(.*)$/
|
115
|
+
name_ = $1
|
116
|
+
Builder.class_eval do
|
117
|
+
define_method(name_) do |*args_|
|
118
|
+
subclass_.new(*args_)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def _interpret_processor_array(param_) # :nodoc:
|
128
|
+
param_.flatten.map{ |processor_| _interpret_processor(processor_) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def _interpret_processor(param_) # :nodoc:
|
132
|
+
case param_
|
133
|
+
when Class
|
134
|
+
param_.new
|
135
|
+
when Base
|
136
|
+
param_
|
137
|
+
else
|
138
|
+
raise ArgumentError, "Unknown processor object of type #{param_.class.name}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# A convenience DSL for building sets of processors. This is typically
|
147
|
+
# useful for constructing if-expressions using the boolean operation
|
148
|
+
# processors.
|
149
|
+
|
150
|
+
def self.build(&block_)
|
151
|
+
::Blockenspiel.invoke(block_, Builder.new)
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
end
|