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
data/History.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ === 0.0.1 / 2009-10-28
2
+
3
+ * Initial test release
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ == Sawmill
2
+
3
+ Sawmill is a logging and log analysis system for Ruby.
4
+ It extends the basic Ruby logging facility with log records and logfile parsing features.
5
+
6
+ === What is it?
7
+
8
+ A user reported a bug in your Rails application, and now you have to figure out what happened. You can spend hours poring over megabytes of text log files, stretching your grep-fu to its snapping point... or you can use Sawmill.
9
+
10
+ Your CEO wants to know how many people viewed the new product pages last week. You can write yet another arcane sed script looking for that elusive pattern in the log files... or you can use Sawmill.
11
+
12
+ Sawmill is an extension to the standard ruby Logger mechanism that enables automated log analysis. Designed especially for web applications using Ruby on Rails and similar frameworks, Sawmill originated in the source to www.geopage.com, where it has been analyzing the production Rails logs for more than three years.
13
+
14
+ === Feature list
15
+
16
+ * Drop-in compatible with standard ruby Logger class
17
+ * Custom log levels
18
+ * Process log entries as objects
19
+ * Group log entries into log records with unique record IDs and attributes
20
+ * Filtering and analysis of log entries and log records
21
+ * Write logfiles, optionally with one of several logfile rotation mechanisms
22
+ * Parse logfiles back into log entries and log records
23
+ * Log analysis framework
24
+ * Rack middleware for quick setup of web service logs
25
+
26
+ === Requirements
27
+
28
+ * Ruby 1.8.6 or later (1.8.7 recommended), Ruby 1.9.1 or later, or JRuby 1.4 or later.
29
+ * versionomy gem.
30
+
31
+ === Installation
32
+
33
+ gem install sawmill
34
+
35
+ === Known issues and limitations
36
+
37
+ Sawmill is currently under development, and some features are not yet complete or fully tested.
38
+
39
+ === Development and support
40
+
41
+ Documentation is available at http://virtuoso.rubyforge.org/sawmill/README_rdoc.html
42
+
43
+ Source code is hosted on Github at http://github.com/dazuma/sawmill
44
+
45
+ Report bugs on Github issues at http://github.org/dazuma/sawmill/issues
46
+
47
+ Contact the author at dazuma at gmail dot com.
48
+
49
+ === Author / Credits
50
+
51
+ Lumber is written by Daniel Azuma (http://www.daniel-azuma.com/).
52
+
53
+ == LICENSE:
54
+
55
+ Copyright 2009 Daniel Azuma.
56
+
57
+ All rights reserved.
58
+
59
+ Redistribution and use in source and binary forms, with or without
60
+ modification, are permitted provided that the following conditions are met:
61
+
62
+ * Redistributions of source code must retain the above copyright notice,
63
+ this list of conditions and the following disclaimer.
64
+ * Redistributions in binary form must reproduce the above copyright notice,
65
+ this list of conditions and the following disclaimer in the documentation
66
+ and/or other materials provided with the distribution.
67
+ * Neither the name of the copyright holder, nor the names of any other
68
+ contributors to this software, may be used to endorse or promote products
69
+ derived from this software without specific prior written permission.
70
+
71
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
72
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
74
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
75
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
78
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
79
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
80
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
81
+ POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,147 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill Rakefile
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
+ require 'rake'
37
+ require 'rake/clean'
38
+ require 'rake/gempackagetask'
39
+ require 'rake/testtask'
40
+ require 'rake/rdoctask'
41
+ require 'rdoc/generator/darkfish'
42
+
43
+ require ::File.expand_path("#{::File.dirname(__FILE__)}/lib/sawmill.rb")
44
+
45
+
46
+ # Configuration
47
+ extra_rdoc_files_ = ['README.rdoc', 'History.rdoc']
48
+
49
+
50
+ # Default task
51
+ task :default => [:clean, :rdoc, :package, :test]
52
+
53
+
54
+ # Clean task
55
+ CLEAN.include(['doc', 'pkg'])
56
+
57
+
58
+ # Test task
59
+ ::Rake::TestTask.new('test') do |task_|
60
+ task_.pattern = 'tests/tc_*.rb'
61
+ end
62
+
63
+
64
+ # RDoc task
65
+ ::Rake::RDocTask.new do |task_|
66
+ task_.main = 'README.rdoc'
67
+ task_.rdoc_files.include(*extra_rdoc_files_)
68
+ task_.rdoc_files.include('lib/sawmill/**/*.rb')
69
+ task_.rdoc_dir = 'doc'
70
+ task_.title = "Sawmill #{::Sawmill::VERSION_STRING} documentation"
71
+ task_.options << '-f' << 'darkfish'
72
+ end
73
+
74
+
75
+ # Gem task
76
+ gemspec_ = ::Gem::Specification.new do |s_|
77
+ s_.name = 'sawmill'
78
+ s_.summary = 'Sawmill is a logging and log analysis system for Ruby.'
79
+ s_.version = ::Sawmill::VERSION_STRING
80
+ s_.author = 'Daniel Azuma'
81
+ s_.email = 'dazuma@gmail.com'
82
+ s_.description = 'Sawmill is a logging and log analysis system for Ruby. It extends the basic Ruby logging facility with log records and parsing abilities.'
83
+ s_.homepage = 'http://github.com/dazuma/sawmill'
84
+ s_.rubyforge_project = 'virtuoso'
85
+ s_.required_ruby_version = '>= 1.8.6'
86
+ s_.files = ::FileList['lib/**/*.rb', 'tests/**/*.rb', '*.rdoc', 'Rakefile'].to_a
87
+ s_.extra_rdoc_files = extra_rdoc_files_
88
+ s_.has_rdoc = true
89
+ s_.test_files = ::FileList['tests/tc_*.rb']
90
+ s_.platform = ::Gem::Platform::RUBY
91
+ s_.add_dependency('blockenspiel', '>= 0.2.1')
92
+ s_.add_dependency('versionomy', '>= 0.1.1')
93
+ end
94
+ ::Rake::GemPackageTask.new(gemspec_) do |task_|
95
+ task_.need_zip = false
96
+ task_.need_tar = true
97
+ end
98
+
99
+
100
+ # Publish RDocs
101
+ desc 'Publishes RDocs to RubyForge'
102
+ task :publish_rdoc_to_rubyforge => [:rerdoc] do
103
+ config_ = ::YAML.load(::File.read(::File.expand_path("~/.rubyforge/user-config.yml")))
104
+ username_ = config_['username']
105
+ sh "rsync -av --delete doc/ #{username_}@rubyforge.org:/var/www/gforge-projects/virtuoso/sawmill"
106
+ end
107
+
108
+
109
+ # Publish gem
110
+ task :publish_gem_to_rubyforge => [:package] do |t_|
111
+ v_ = ::ENV["VERSION"]
112
+ abort "Must supply VERSION=x.y.z" unless v_
113
+ if v_ != ::Sawmill::VERSION_STRING
114
+ abort "Versions don't match: #{v_} vs #{::Sawmill::VERSION_STRING}"
115
+ end
116
+ gem_pkg_ = "pkg/sawmill-#{v_}.gem"
117
+ tgz_pkg_ = "pkg/sawmill-#{v_}.tgz"
118
+ release_notes_ = ::File.read("README.rdoc").split(/^(==.*)/)[2].strip
119
+ release_changes_ = ::File.read("History.rdoc").split(/^(===.*)/)[1..2].join.strip
120
+
121
+ require 'rubyforge'
122
+ rf_ = ::RubyForge.new.configure
123
+ puts "Logging in to RubyForge"
124
+ rf_.login
125
+ config_ = rf_.userconfig
126
+ config_["release_notes"] = release_notes_
127
+ config_["release_changes"] = release_changes_
128
+ config_["preformatted"] = true
129
+ puts "Releasing sawmill #{v_} to RubyForge"
130
+ rf_.add_release('virtuoso', 'sawmill', v_, gem_pkg_, tgz_pkg_)
131
+ end
132
+
133
+
134
+ # Publish gem
135
+ task :publish_gem_to_gemcutter => [:package] do |t_|
136
+ v_ = ::ENV["VERSION"]
137
+ abort "Must supply VERSION=x.y.z" unless v_
138
+ if v_ != ::Sawmill::VERSION_STRING
139
+ abort "Versions don't match: #{v_} vs #{::Sawmill::VERSION_STRING}"
140
+ end
141
+ puts "Releasing sawmill #{v_} to GemCutter"
142
+ `cd pkg && gem push sawmill-#{v_}.gem`
143
+ end
144
+
145
+
146
+ # Publish everything
147
+ task :publish => [:publish_gem_to_gemcutter, :publish_gem_to_rubyforge, :publish_rdoc_to_rubyforge]
@@ -0,0 +1,307 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill log entry classes
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
+ # This module is a namespace for log entry classes.
41
+
42
+ module Entry
43
+
44
+
45
+ # A log entry that doesn't conform to sawmill's format.
46
+
47
+ class UnknownData
48
+
49
+
50
+ def initialize(line_)
51
+ @line = line_.to_s
52
+ end
53
+
54
+
55
+ # Returns <tt>:unknown_data</tt>
56
+ def type; :unknown_data end
57
+
58
+ # The line in the logfile as a raw string
59
+ attr_reader :line
60
+
61
+
62
+ def to_s # :nodoc:
63
+ "#{type}: #{@line}"
64
+ end
65
+
66
+ def inspect # :nodoc:
67
+ "#<#{self.class}:0x#{object_id.to_s(16)} line=#{@line.inspect}>"
68
+ end
69
+
70
+ def eql?(obj_) # :nodoc:
71
+ obj_.kind_of?(Entry::UnknownData) && obj_.line == @line
72
+ end
73
+
74
+ def ==(obj_) # :nodoc:
75
+ eql?(obj_)
76
+ end
77
+
78
+ def hash # :nodoc:
79
+ type.hash ^ @line.hash
80
+ end
81
+
82
+ end
83
+
84
+
85
+ # A log entry containing a standard log message.
86
+
87
+ class Message
88
+
89
+
90
+ def initialize(level_, timestamp_, progname_, record_id_, message_)
91
+ @level = level_
92
+ @timestamp = timestamp_
93
+ @progname = progname_.to_s
94
+ @progname.gsub!(/\s+/, '')
95
+ @record_id = record_id_.nil? ? nil : record_id_.to_s
96
+ @record_id.gsub!(/\s+/, '') if @record_id
97
+ @message = message_.to_s
98
+ end
99
+
100
+
101
+ # Returns <tt>:message</tt>
102
+ def type; :message; end
103
+
104
+ # The log level as a Sawmill::Level object
105
+ attr_reader :level
106
+ # The timestamp as a Time object
107
+ attr_reader :timestamp
108
+ # The progname as a string
109
+ attr_reader :progname
110
+ # The record ID as a string
111
+ attr_reader :record_id
112
+ # The message as a string
113
+ attr_reader :message
114
+
115
+
116
+ def to_s # :nodoc:
117
+ "#{type}: #{@message}"
118
+ end
119
+
120
+ def inspect # :nodoc:
121
+ "#<#{self.class}:0x#{object_id.to_s(16)} level=#{@level.name} time=#{@timestamp.to_s.inspect} progname=#{@progname.inspect} record_id=#{@record_id.inspect} message=#{@message.inspect}>"
122
+ end
123
+
124
+ def eql?(obj_) # :nodoc:
125
+ obj_.kind_of?(Entry::Message) && obj_.level == @level && obj_.timestamp == @timestamp && obj_.progname == @progname && obj_.record_id == @record_id && obj_.message == @message
126
+ end
127
+
128
+ def ==(obj_) # :nodoc:
129
+ eql?(obj_)
130
+ end
131
+
132
+ def hash # :nodoc:
133
+ type.hash ^ @level.hash ^ @timestamp.hash ^ @progname.hash ^ @record_id.hash ^ @message.hash
134
+ end
135
+
136
+
137
+ end
138
+
139
+
140
+ # A log entry signalling the beginning of a log record.
141
+
142
+ class BeginRecord
143
+
144
+
145
+ def initialize(level_, timestamp_, progname_, record_id_)
146
+ @level = level_
147
+ @timestamp = timestamp_
148
+ @progname = progname_.to_s
149
+ @progname.gsub!(/\s+/, '')
150
+ @record_id = record_id_.nil? ? nil : record_id_.to_s
151
+ @record_id.gsub!(/\s+/, '') if @record_id
152
+ end
153
+
154
+
155
+ # Returns <tt>:begin_record</tt>
156
+ def type; :begin_record; end
157
+
158
+ # The log level as a Sawmill::Level object
159
+ attr_reader :level
160
+ # The timestamp as a Time object
161
+ attr_reader :timestamp
162
+ # The progname as a string
163
+ attr_reader :progname
164
+ # The record ID as a string
165
+ attr_reader :record_id
166
+
167
+
168
+ def to_s # :nodoc:
169
+ "#{type}: #{@record_id}"
170
+ end
171
+
172
+ def inspect # :nodoc:
173
+ "#<#{self.class}:0x#{object_id.to_s(16)} level=#{@level.name} time=#{@timestamp.to_s.inspect} progname=#{@progname.inspect} record_id=#{@record_id.inspect}>"
174
+ end
175
+
176
+ def eql?(obj_) # :nodoc:
177
+ obj_.kind_of?(Entry::BeginRecord) && obj_.level == @level && obj_.timestamp == @timestamp && obj_.progname == @progname && obj_.record_id == @record_id
178
+ end
179
+
180
+ def ==(obj_) # :nodoc:
181
+ eql?(obj_)
182
+ end
183
+
184
+ def hash # :nodoc:
185
+ type.hash ^ @level.hash ^ @timestamp.hash ^ @progname.hash ^ @record_id.hash
186
+ end
187
+
188
+
189
+ end
190
+
191
+
192
+ # A log entry signalling the end of a log record.
193
+
194
+ class EndRecord
195
+
196
+
197
+ def initialize(level_, timestamp_, progname_, record_id_)
198
+ @level = level_
199
+ @timestamp = timestamp_
200
+ @progname = progname_.to_s
201
+ @record_id = record_id_.nil? ? nil : record_id_.to_s
202
+ end
203
+
204
+
205
+ # Returns <tt>:end_record</tt>
206
+ def type; :end_record; end
207
+
208
+ # The log level as a Sawmill::Level object
209
+ attr_reader :level
210
+ # The timestamp as a Time object
211
+ attr_reader :timestamp
212
+ # The progname as a string
213
+ attr_reader :progname
214
+ # The record ID as a string
215
+ attr_reader :record_id
216
+
217
+
218
+ def to_s # :nodoc:
219
+ "#{type}: #{@record_id}"
220
+ end
221
+
222
+ def inspect # :nodoc:
223
+ "#<#{self.class}:0x#{object_id.to_s(16)} level=#{@level.name} time=#{@timestamp.to_s.inspect} progname=#{@progname.inspect} record_id=#{@record_id.inspect}>"
224
+ end
225
+
226
+ def eql?(obj_) # :nodoc:
227
+ obj_.kind_of?(Entry::EndRecord) && obj_.level == @level && obj_.timestamp == @timestamp && obj_.progname == @progname && obj_.record_id == @record_id
228
+ end
229
+
230
+ def ==(obj_) # :nodoc:
231
+ eql?(obj_)
232
+ end
233
+
234
+ def hash # :nodoc:
235
+ type.hash ^ @level.hash ^ @timestamp.hash ^ @progname.hash ^ @record_id.hash
236
+ end
237
+
238
+
239
+ end
240
+
241
+
242
+ # A log entry containing a log record attribute.
243
+
244
+ class Attribute
245
+
246
+
247
+ def initialize(level_, timestamp_, progname_, record_id_, key_, value_, operation_=nil)
248
+ @level = level_
249
+ @timestamp = timestamp_
250
+ @progname = progname_.to_s
251
+ @progname.gsub!(/\s+/, '')
252
+ @record_id = record_id_.nil? ? nil : record_id_.to_s
253
+ @record_id.gsub!(/\s+/, '') if @record_id
254
+ @key = key_.to_s
255
+ @key.gsub!(/\s+/, '')
256
+ @value = value_.to_s
257
+ @operation = operation_ || :set
258
+ end
259
+
260
+
261
+ # Returns <tt>:attribute</tt>
262
+ def type; :attribute; end
263
+
264
+ # The log level as a Sawmill::Level object
265
+ attr_reader :level
266
+ # The timestamp as a Time object
267
+ attr_reader :timestamp
268
+ # The progname as a string
269
+ attr_reader :progname
270
+ # The record ID as a string
271
+ attr_reader :record_id
272
+ # The operation, which can be :set, :append, :remove, :unset
273
+ attr_reader :operation
274
+ # The attribute key as a string
275
+ attr_reader :key
276
+ # The attribute value as a string
277
+ attr_reader :value
278
+
279
+
280
+ def to_s # :nodoc:
281
+ "#{type}: #{@key}=#{@value.inspect}"
282
+ end
283
+
284
+ def inspect # :nodoc:
285
+ "#<#{self.class}:0x#{object_id.to_s(16)} level=#{@level.name} time=#{@timestamp.to_s.inspect} progname=#{@progname.inspect} record_id=#{@record_id.inspect} operation=#{@operation} key=#{@key.inspect} value=#{@value.inspect}>"
286
+ end
287
+
288
+ def eql?(obj_) # :nodoc:
289
+ obj_.kind_of?(Entry::Attribute) && obj_.level == @level && obj_.timestamp == @timestamp && obj_.progname == @progname && obj_.record_id == @record_id && obj_.key == @key && obj_.value == @value && obj_.operation == @operation
290
+ end
291
+
292
+ def ==(obj_) # :nodoc:
293
+ eql?(obj_)
294
+ end
295
+
296
+ def hash # :nodoc:
297
+ type.hash ^ @level.hash ^ @timestamp.hash ^ @progname.hash ^ @record_id.hash ^ @key.hash ^ @value.hash ^ @operation.hash
298
+ end
299
+
300
+
301
+ end
302
+
303
+
304
+ end
305
+
306
+
307
+ end
@@ -0,0 +1,75 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill entry sorter 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
+
40
+ # An object that classifies log entry objects, calling the proper methods
41
+ # on a Sawmill::EntryProcessor.
42
+
43
+ class EntryClassifier
44
+
45
+
46
+ # Create a classifier that sends entries to the given
47
+ # Sawmill::EntryProcessor.
48
+
49
+ def initialize(processor_)
50
+ @processor = processor_
51
+ end
52
+
53
+
54
+ # Call this method to classify a log entry and send it to the processor.
55
+
56
+ def entry(entry_)
57
+ case entry_.type
58
+ when :unknown_data
59
+ @processor.unknown_data(entry_)
60
+ when :begin_record
61
+ @processor.begin_record(entry_)
62
+ when :end_record
63
+ @processor.end_record(entry_)
64
+ when :message
65
+ @processor.message(entry_)
66
+ when :attribute
67
+ @processor.attribute(entry_)
68
+ end
69
+ end
70
+
71
+
72
+ end
73
+
74
+
75
+ end