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