sawmill 0.0.1 → 0.0.2
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 +6 -0
- data/Rakefile +8 -8
- data/lib/sawmill/entry_processor/filter_basic_fields.rb +1 -1
- data/lib/sawmill/entry_processor/format.rb +2 -2
- data/lib/sawmill/entry_processor/simple_queue.rb +7 -0
- data/lib/sawmill/entry_processor.rb +2 -2
- data/lib/sawmill/log_record_middleware.rb +3 -3
- data/lib/sawmill/logger.rb +27 -24
- data/lib/sawmill/multi_parser.rb +127 -0
- data/lib/sawmill/parser.rb +6 -7
- data/lib/sawmill/record.rb +12 -2
- data/lib/sawmill/record_processor/decompose.rb +1 -1
- data/lib/sawmill/record_processor/filter_by_attributes.rb +2 -2
- data/lib/sawmill/record_processor/simple_queue.rb +14 -0
- data/lib/sawmill/record_processor.rb +2 -2
- data/lib/sawmill/rotater/base.rb +1 -1
- data/lib/sawmill/rotater/date_based_log_file.rb +4 -4
- data/lib/sawmill/rotater/shifting_log_file.rb +11 -11
- data/lib/sawmill/rotater.rb +2 -2
- data/lib/sawmill/util/heap.rb +153 -0
- data/lib/sawmill/util/queue.rb +27 -1
- data/lib/sawmill/version.rb +1 -1
- data/lib/sawmill.rb +2 -0
- data/tests/tc_multi_parser.rb +88 -0
- metadata +8 -4
data/History.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -80,7 +80,7 @@ gemspec_ = ::Gem::Specification.new do |s_|
|
|
80
80
|
s_.author = 'Daniel Azuma'
|
81
81
|
s_.email = 'dazuma@gmail.com'
|
82
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://
|
83
|
+
s_.homepage = 'http://virtuoso.rubyforge.org/sawmill'
|
84
84
|
s_.rubyforge_project = 'virtuoso'
|
85
85
|
s_.required_ruby_version = '>= 1.8.6'
|
86
86
|
s_.files = ::FileList['lib/**/*.rb', 'tests/**/*.rb', '*.rdoc', 'Rakefile'].to_a
|
@@ -88,8 +88,8 @@ gemspec_ = ::Gem::Specification.new do |s_|
|
|
88
88
|
s_.has_rdoc = true
|
89
89
|
s_.test_files = ::FileList['tests/tc_*.rb']
|
90
90
|
s_.platform = ::Gem::Platform::RUBY
|
91
|
-
s_.add_dependency('blockenspiel', '>= 0.2.
|
92
|
-
s_.add_dependency('versionomy', '>= 0.1.
|
91
|
+
s_.add_dependency('blockenspiel', '>= 0.2.2')
|
92
|
+
s_.add_dependency('versionomy', '>= 0.1.2')
|
93
93
|
end
|
94
94
|
::Rake::GemPackageTask.new(gemspec_) do |task_|
|
95
95
|
task_.need_zip = false
|
@@ -106,8 +106,8 @@ task :publish_rdoc_to_rubyforge => [:rerdoc] do
|
|
106
106
|
end
|
107
107
|
|
108
108
|
|
109
|
-
#
|
110
|
-
task :
|
109
|
+
# Release gem ro rubyforge
|
110
|
+
task :release_gem_to_rubyforge => [:package] do |t_|
|
111
111
|
v_ = ::ENV["VERSION"]
|
112
112
|
abort "Must supply VERSION=x.y.z" unless v_
|
113
113
|
if v_ != ::Sawmill::VERSION_STRING
|
@@ -131,8 +131,8 @@ task :publish_gem_to_rubyforge => [:package] do |t_|
|
|
131
131
|
end
|
132
132
|
|
133
133
|
|
134
|
-
#
|
135
|
-
task :
|
134
|
+
# Release gem to gemcutter
|
135
|
+
task :release_gem_to_gemcutter => [:package] do |t_|
|
136
136
|
v_ = ::ENV["VERSION"]
|
137
137
|
abort "Must supply VERSION=x.y.z" unless v_
|
138
138
|
if v_ != ::Sawmill::VERSION_STRING
|
@@ -144,4 +144,4 @@ end
|
|
144
144
|
|
145
145
|
|
146
146
|
# Publish everything
|
147
|
-
task :
|
147
|
+
task :release => [:release_gem_to_gemcutter, :release_gem_to_rubyforge, :publish_rdoc_to_rubyforge]
|
@@ -119,7 +119,7 @@ module Sawmill
|
|
119
119
|
def _check_filter(entry_) # :nodoc:
|
120
120
|
if @level
|
121
121
|
level_ = entry_.level
|
122
|
-
if @level.kind_of?(
|
122
|
+
if @level.kind_of?(Level)
|
123
123
|
check_level_ = @level
|
124
124
|
if level_.group != check_level_.group
|
125
125
|
return false unless @accept_incomparable_levels
|
@@ -74,7 +74,7 @@ module Sawmill
|
|
74
74
|
elsif destination_.respond_to?(:close) && destination_.respond_to?(:write)
|
75
75
|
@io = destination_
|
76
76
|
else
|
77
|
-
raise ArgumentError, "Unknown destination type"
|
77
|
+
raise ::ArgumentError, "Unknown destination type"
|
78
78
|
end
|
79
79
|
@include_id = opts_[:include_id]
|
80
80
|
@fractional_second_digits = (opts_[:fractional_second_digits] || 2).to_i
|
@@ -139,7 +139,7 @@ module Sawmill
|
|
139
139
|
|
140
140
|
def unknown_data(entry_)
|
141
141
|
return false unless @io || @rotater
|
142
|
-
_write_str(entry_.line+"\n",
|
142
|
+
_write_str(entry_.line+"\n", nil)
|
143
143
|
true
|
144
144
|
end
|
145
145
|
|
@@ -130,12 +130,12 @@ module Sawmill
|
|
130
130
|
|
131
131
|
def _interpret_processor(param_) # :nodoc:
|
132
132
|
case param_
|
133
|
-
when Class
|
133
|
+
when ::Class
|
134
134
|
param_.new
|
135
135
|
when Base
|
136
136
|
param_
|
137
137
|
else
|
138
|
-
raise ArgumentError, "Unknown processor object of type #{param_.class.name}"
|
138
|
+
raise ::ArgumentError, "Unknown processor object of type #{param_.class.name}"
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
@@ -62,7 +62,7 @@ module Sawmill
|
|
62
62
|
|
63
63
|
def initialize(app_, logger_=nil, opts_={})
|
64
64
|
@app = app_
|
65
|
-
@logger = logger_ || Logger.new(:progname => 'rack', :processor =>
|
65
|
+
@logger = logger_ || Logger.new(:progname => 'rack', :processor => Formatter.new(::STDOUT))
|
66
66
|
@request_id_key = opts_[:request_id_key] || 'sawmill.request_id'
|
67
67
|
@start_time_attribute = opts_[:start_time_attribute]
|
68
68
|
@end_time_attribute = opts_[:end_time_attribute]
|
@@ -72,14 +72,14 @@ module Sawmill
|
|
72
72
|
def call(env_)
|
73
73
|
env_[@request_id_key] = @logger.begin_record
|
74
74
|
if @start_time_attribute
|
75
|
-
time_ = Time.now.utc
|
75
|
+
time_ = ::Time.now.utc
|
76
76
|
@logger.set_attribute(@start_time_attribute, time_.strftime('%Y-%m-%dT%H:%M:%S.') + ('%06d' % time_.usec) + 'Z')
|
77
77
|
end
|
78
78
|
begin
|
79
79
|
return @app.call(env_)
|
80
80
|
ensure
|
81
81
|
if @end_time_attribute
|
82
|
-
time_ = Time.now.utc
|
82
|
+
time_ = ::Time.now.utc
|
83
83
|
@logger.set_attribute(@end_time_attribute, time_.strftime('%Y-%m-%dT%H:%M:%S.') + ('%06d' % time_.usec) + 'Z')
|
84
84
|
end
|
85
85
|
@logger.end_record
|
data/lib/sawmill/logger.rb
CHANGED
@@ -34,8 +34,9 @@
|
|
34
34
|
;
|
35
35
|
|
36
36
|
|
37
|
-
|
37
|
+
begin
|
38
38
|
require 'securerandom'
|
39
|
+
rescue ::LoadError
|
39
40
|
end
|
40
41
|
|
41
42
|
|
@@ -80,7 +81,7 @@ module Sawmill
|
|
80
81
|
# If not specified, log entries are written out to STDOUT.
|
81
82
|
|
82
83
|
def initialize(opts_={})
|
83
|
-
@levels = opts_[:levels] ||
|
84
|
+
@levels = opts_[:levels] || STANDARD_LEVELS
|
84
85
|
@level = @levels.get(opts_[:level])
|
85
86
|
if opts_.include?(:attribute_level)
|
86
87
|
@attribute_level = @levels.get(opts_[:attribute_level])
|
@@ -89,8 +90,8 @@ module Sawmill
|
|
89
90
|
end
|
90
91
|
@progname = opts_[:progname] || 'sawmill'
|
91
92
|
@record_progname = opts_[:record_progname] || @progname
|
92
|
-
@record_id_generator = opts_[:record_id_generator] || _get_default_record_id_generator
|
93
|
-
@processor = opts_[:processor] ||
|
93
|
+
@record_id_generator = opts_[:record_id_generator] || Logger._get_default_record_id_generator
|
94
|
+
@processor = opts_[:processor] || Formatter.new(::STDOUT)
|
94
95
|
@current_record_id = nil
|
95
96
|
end
|
96
97
|
|
@@ -122,7 +123,7 @@ module Sawmill
|
|
122
123
|
else
|
123
124
|
message_ = message_.inspect
|
124
125
|
end
|
125
|
-
@processor.message(Entry::Message.new(level_obj_, Time.now, progname_, @current_record_id, message_))
|
126
|
+
@processor.message(Entry::Message.new(level_obj_, ::Time.now, progname_, @current_record_id, message_))
|
126
127
|
true
|
127
128
|
end
|
128
129
|
alias_method :log, :add
|
@@ -161,7 +162,7 @@ module Sawmill
|
|
161
162
|
def begin_record(id_=nil)
|
162
163
|
end_record if @current_record_id
|
163
164
|
@current_record_id = (id_ || @record_id_generator.call).to_s
|
164
|
-
@processor.begin_record(Entry::BeginRecord.new(@levels.highest, Time.now, @record_progname, @current_record_id))
|
165
|
+
@processor.begin_record(Entry::BeginRecord.new(@levels.highest, ::Time.now, @record_progname, @current_record_id))
|
165
166
|
@current_record_id
|
166
167
|
end
|
167
168
|
|
@@ -180,7 +181,7 @@ module Sawmill
|
|
180
181
|
|
181
182
|
def end_record
|
182
183
|
if @current_record_id
|
183
|
-
@processor.end_record(Entry::EndRecord.new(@levels.highest, Time.now, @record_progname, @current_record_id))
|
184
|
+
@processor.end_record(Entry::EndRecord.new(@levels.highest, ::Time.now, @record_progname, @current_record_id))
|
184
185
|
id_ = @current_record_id
|
185
186
|
@current_record_id = nil
|
186
187
|
id_
|
@@ -209,7 +210,7 @@ module Sawmill
|
|
209
210
|
end
|
210
211
|
end
|
211
212
|
return true if level_obj_ < @level
|
212
|
-
@processor.attribute(Entry::Attribute.new(level_obj_, Time.now, progname_ || @record_progname, @current_record_id, key_, value_, operation_))
|
213
|
+
@processor.attribute(Entry::Attribute.new(level_obj_, ::Time.now, progname_ || @record_progname, @current_record_id, key_, value_, operation_))
|
213
214
|
true
|
214
215
|
end
|
215
216
|
|
@@ -288,7 +289,7 @@ module Sawmill
|
|
288
289
|
# a default generator which uses the variant 4 (random) UUID standard.
|
289
290
|
|
290
291
|
def to_generate_record_id(&block_)
|
291
|
-
@record_id_generator = block_ || _get_default_record_id_generator
|
292
|
+
@record_id_generator = block_ || Logger._get_default_record_id_generator
|
292
293
|
end
|
293
294
|
|
294
295
|
|
@@ -339,21 +340,23 @@ module Sawmill
|
|
339
340
|
end
|
340
341
|
|
341
342
|
|
342
|
-
def _get_default_record_id_generator # :nodoc:
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
343
|
+
def self._get_default_record_id_generator # :nodoc:
|
344
|
+
unless @_default_generator
|
345
|
+
if defined?(::SecureRandom)
|
346
|
+
def self._random_hex32
|
347
|
+
::SecureRandom.hex(32)
|
348
|
+
end
|
349
|
+
elsif defined?(::ActiveSupport::SecureRandom)
|
350
|
+
def self._random_hex32
|
351
|
+
::ActiveSupport::SecureRandom.hex(32)
|
352
|
+
end
|
353
|
+
else
|
354
|
+
def self._random_hex32
|
355
|
+
::Kernel.rand(0x100000000000000000000000000000000).to_s(16).rjust(32, '0')
|
356
|
+
end
|
353
357
|
end
|
354
|
-
|
355
|
-
|
356
|
-
uuid_ = Kernel.rand(0x100000000000000000000000000000000).to_s(16).rjust(32, '0')
|
358
|
+
@_default_generator = ::Proc.new do
|
359
|
+
uuid_ = _random_hex32
|
357
360
|
uuid_[12] = '4'
|
358
361
|
uuid_[16] = (uuid_[16,1].to_i(16)&3|8).to_s(16)
|
359
362
|
uuid_.insert(8, '-')
|
@@ -363,8 +366,8 @@ module Sawmill
|
|
363
366
|
uuid_
|
364
367
|
end
|
365
368
|
end
|
369
|
+
@_default_generator
|
366
370
|
end
|
367
|
-
private :_get_default_record_id_generator
|
368
371
|
|
369
372
|
|
370
373
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill multi-stream parser 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
|
+
# A logfile parser that parses log entries from multiple logfile streams,
|
41
|
+
# sorts by timestamp, and sends them to a processor.
|
42
|
+
|
43
|
+
class MultiParser
|
44
|
+
|
45
|
+
|
46
|
+
# Create a new parser that reads from the given streams.
|
47
|
+
#
|
48
|
+
# You should provide a processor to receive the data from the logfile.
|
49
|
+
# The processor may be either an entry processor or a record processor.
|
50
|
+
# You may also pass nil for the processor. In this case, the generated
|
51
|
+
# log entries will not be sent to a processor but will still be returned
|
52
|
+
# by the parse_one_entry method.
|
53
|
+
#
|
54
|
+
# Recognized options include:
|
55
|
+
#
|
56
|
+
# <tt>:levels</tt>
|
57
|
+
# Sawmill::LevelGroup to use to parse log levels.
|
58
|
+
# If not specified, Sawmill::STANDARD_LEVELS is used by default.
|
59
|
+
# <tt>:emit_incomplete_records_at_eof</tt>
|
60
|
+
# If set to true, causes any incomplete log records to be emitted
|
61
|
+
# in their incomplete state when EOF is reached on all streams.
|
62
|
+
|
63
|
+
def initialize(io_array_, processor_, opts_={})
|
64
|
+
@emit_incomplete_records_at_eof = opts_.delete(:emit_incomplete_records_at_eof)
|
65
|
+
@heap = Util::Heap.new{ |a_, b_| a_[1].timestamp <=> b_[1].timestamp }
|
66
|
+
@queue = Util::Queue.new
|
67
|
+
io_array_.each{ |io_| _enqueue(Parser.new(io_, nil, opts_)) }
|
68
|
+
@processor = nil
|
69
|
+
if processor_.respond_to?(:record) && processor_.respond_to?(:extra_entry)
|
70
|
+
@processor = RecordBuilder.new(processor_)
|
71
|
+
elsif processor_.respond_to?(:begin_record) && processor_.respond_to?(:end_record)
|
72
|
+
@processor = processor_
|
73
|
+
end
|
74
|
+
@classifier = @processor ? EntryClassifier.new(@processor) : nil
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Parse one log entry from the streams and emit it to the processor.
|
79
|
+
# Also returns the log entry.
|
80
|
+
# Returns nil if EOF has been reached on all streams.
|
81
|
+
|
82
|
+
def parse_one_entry
|
83
|
+
entry_ = @queue.dequeue
|
84
|
+
unless entry_
|
85
|
+
data_ = @heap.remove
|
86
|
+
if data_
|
87
|
+
_enqueue(data_[0])
|
88
|
+
entry_ = data_[1]
|
89
|
+
else
|
90
|
+
if @emit_incomplete_records_at_eof && @processor.respond_to?(:emit_incomplete_records)
|
91
|
+
@processor.emit_incomplete_records
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@classifier.entry(entry_) if entry_
|
96
|
+
entry_
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Parse until EOF is reached on all streams, and emit the log
|
101
|
+
# entries to the processor.
|
102
|
+
|
103
|
+
def parse_all
|
104
|
+
while parse_one_entry; end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def _enqueue(parser_) # :nodoc:
|
111
|
+
loop do
|
112
|
+
entry_ = parser_.parse_one_entry
|
113
|
+
return unless entry_
|
114
|
+
if entry_.type == :unknown_data
|
115
|
+
@queue.enqueue(entry_)
|
116
|
+
else
|
117
|
+
@heap << [parser_, entry_]
|
118
|
+
return
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
end
|
data/lib/sawmill/parser.rb
CHANGED
@@ -62,21 +62,20 @@ module Sawmill
|
|
62
62
|
# <tt>:levels</tt>
|
63
63
|
# Sawmill::LevelGroup to use to parse log levels.
|
64
64
|
# If not specified, Sawmill::STANDARD_LEVELS is used by default.
|
65
|
-
# <tt>:
|
65
|
+
# <tt>:emit_incomplete_records_at_eof</tt>
|
66
66
|
# If set to true, causes any incomplete log records to be emitted
|
67
67
|
# in their incomplete state when EOF is reached.
|
68
68
|
|
69
69
|
def initialize(io_, processor_, opts_={})
|
70
70
|
@io = io_
|
71
|
-
@record_processor = nil
|
72
71
|
@processor = nil
|
73
72
|
if processor_.respond_to?(:record) && processor_.respond_to?(:extra_entry)
|
74
73
|
@processor = RecordBuilder.new(processor_)
|
75
74
|
elsif processor_.respond_to?(:begin_record) && processor_.respond_to?(:end_record)
|
76
75
|
@processor = processor_
|
77
76
|
end
|
78
|
-
@levels = opts_[:levels] ||
|
79
|
-
@
|
77
|
+
@levels = opts_[:levels] || STANDARD_LEVELS
|
78
|
+
@emit_incomplete_records_at_eof = opts_[:emit_incomplete_records_at_eof]
|
80
79
|
@current_record_id = nil
|
81
80
|
@parser_directives = {}
|
82
81
|
end
|
@@ -155,11 +154,11 @@ module Sawmill
|
|
155
154
|
if str_ =~ DIRECTIVE_REGEXP
|
156
155
|
@parser_directives[$1] = $2
|
157
156
|
end
|
158
|
-
entry_ = Entry::UnknownData.new(str_)
|
157
|
+
entry_ = Entry::UnknownData.new(str_.chomp)
|
159
158
|
@processor.unknown_data(entry_) if @processor.respond_to?(:unknown_data)
|
160
159
|
end
|
161
160
|
else
|
162
|
-
if @
|
161
|
+
if @emit_incomplete_records_at_eof && @processor.respond_to?(:emit_incomplete_records)
|
163
162
|
@processor.emit_incomplete_records
|
164
163
|
end
|
165
164
|
end
|
@@ -171,7 +170,7 @@ module Sawmill
|
|
171
170
|
# entries to the processor.
|
172
171
|
|
173
172
|
def parse_all
|
174
|
-
while
|
173
|
+
while parse_one_entry; end
|
175
174
|
end
|
176
175
|
|
177
176
|
|
data/lib/sawmill/record.rb
CHANGED
@@ -89,6 +89,16 @@ module Sawmill
|
|
89
89
|
end
|
90
90
|
|
91
91
|
|
92
|
+
def eql?(obj_) # :nodoc:
|
93
|
+
return false unless obj_.kind_of?(Record)
|
94
|
+
return @entries == obj_.instance_variable_get(:@entries)
|
95
|
+
end
|
96
|
+
|
97
|
+
def ==(obj_) # :nodoc:
|
98
|
+
eql?(obj_)
|
99
|
+
end
|
100
|
+
|
101
|
+
|
92
102
|
# Append a log entry to this record.
|
93
103
|
#
|
94
104
|
# Entries must be added in order. Raises Errors::IllegalRecordError if
|
@@ -132,9 +142,9 @@ module Sawmill
|
|
132
142
|
when :append
|
133
143
|
val_ = @attributes[entry_.key]
|
134
144
|
case val_
|
135
|
-
when Array
|
145
|
+
when ::Array
|
136
146
|
val_ << entry_.value
|
137
|
-
when String
|
147
|
+
when ::String
|
138
148
|
@attributes[entry_.key] = [val_, entry_.value]
|
139
149
|
when nil
|
140
150
|
@attributes[entry_.key] = [entry_.value]
|
@@ -61,9 +61,9 @@ module Sawmill
|
|
61
61
|
@attributes.each do |key_, value_|
|
62
62
|
record_value_ = record_.attribute(key_.to_s)
|
63
63
|
case record_value_
|
64
|
-
when Array
|
64
|
+
when ::Array
|
65
65
|
return false unless record_value_.find{ |rval_| value_ === rval_ }
|
66
|
-
when String
|
66
|
+
when ::String
|
67
67
|
return false unless value_ === record_value_
|
68
68
|
when nil
|
69
69
|
return false unless value_.nil?
|
@@ -73,6 +73,13 @@ module Sawmill
|
|
73
73
|
end
|
74
74
|
|
75
75
|
|
76
|
+
# Return an array of the contents of the record queue, in order.
|
77
|
+
|
78
|
+
def dequeue_all
|
79
|
+
@queue.dequeue_all
|
80
|
+
end
|
81
|
+
|
82
|
+
|
76
83
|
# Return the number of records in the record queue.
|
77
84
|
|
78
85
|
def size
|
@@ -88,6 +95,13 @@ module Sawmill
|
|
88
95
|
end
|
89
96
|
|
90
97
|
|
98
|
+
# Return an array of the contents of the extra entry queue, in order.
|
99
|
+
|
100
|
+
def dequeue_all_extra_entries
|
101
|
+
@extra_entries_queue.dequeue_all
|
102
|
+
end
|
103
|
+
|
104
|
+
|
91
105
|
# Return the number of entries in the extra entry queue.
|
92
106
|
|
93
107
|
def extra_entries_size
|
@@ -109,12 +109,12 @@ module Sawmill
|
|
109
109
|
|
110
110
|
def _interpret_processor(param_) # :nodoc:
|
111
111
|
case param_
|
112
|
-
when Class
|
112
|
+
when ::Class
|
113
113
|
param_.new
|
114
114
|
when Base
|
115
115
|
param_
|
116
116
|
else
|
117
|
-
raise ArgumentError, "Unknown processor object of type #{param_.class.name}"
|
117
|
+
raise ::ArgumentError, "Unknown processor object of type #{param_.class.name}"
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
data/lib/sawmill/rotater/base.rb
CHANGED
@@ -82,8 +82,8 @@ module Sawmill
|
|
82
82
|
|
83
83
|
def initialize(options_)
|
84
84
|
@turnover_frequency = options_[:turnover_frequency] || :none
|
85
|
-
dirname_ = options_[:dirname] || Dir.getwd
|
86
|
-
@prefix = File.join(dirname_, options_[:prefix] || 'sawmill')
|
85
|
+
dirname_ = options_[:dirname] || ::Dir.getwd
|
86
|
+
@prefix = ::File.join(dirname_, options_[:prefix] || 'sawmill')
|
87
87
|
@suffix = options_[:suffix] || '.log'
|
88
88
|
@local_timezone = options_[:local_timezone]
|
89
89
|
@date_pattern =
|
@@ -101,7 +101,7 @@ module Sawmill
|
|
101
101
|
|
102
102
|
def preferred_handle
|
103
103
|
if @date_pattern
|
104
|
-
time_ = Time.now
|
104
|
+
time_ = ::Time.now
|
105
105
|
time_.utc unless @local_timezone
|
106
106
|
time_.strftime(@date_pattern)
|
107
107
|
else
|
@@ -118,7 +118,7 @@ module Sawmill
|
|
118
118
|
else
|
119
119
|
path_ = @prefix+@suffix
|
120
120
|
end
|
121
|
-
file_ = File.open(path_, File::CREAT | File::WRONLY | File::APPEND)
|
121
|
+
file_ = ::File.open(path_, ::File::CREAT | ::File::WRONLY | ::File::APPEND)
|
122
122
|
file_.sync = true
|
123
123
|
file_
|
124
124
|
end
|
@@ -91,11 +91,11 @@ module Sawmill
|
|
91
91
|
end
|
92
92
|
@history_size = options_[:history_size].to_i
|
93
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')
|
94
|
+
dirname_ = options_[:dirname] || ::Dir.getwd
|
95
|
+
@normal_path = ::File.join(dirname_, options_[:filename] || 'sawmill.log')
|
96
96
|
@preferred_handle = 0
|
97
97
|
@open_handles = {}
|
98
|
-
@last_shift = Time.now
|
98
|
+
@last_shift = ::Time.now
|
99
99
|
end
|
100
100
|
|
101
101
|
|
@@ -114,7 +114,7 @@ module Sawmill
|
|
114
114
|
else
|
115
115
|
path_ = "#{@normal_path}.#{@preferred_handle-handle_-1}"
|
116
116
|
end
|
117
|
-
file_ = File.open(path_, File::CREAT | File::WRONLY | File::APPEND)
|
117
|
+
file_ = ::File.open(path_, ::File::CREAT | ::File::WRONLY | ::File::APPEND)
|
118
118
|
file_.sync = true
|
119
119
|
@open_handles[handle_] = true
|
120
120
|
file_
|
@@ -126,7 +126,7 @@ module Sawmill
|
|
126
126
|
def close_handle(handle_, io_)
|
127
127
|
io_.close
|
128
128
|
if @preferred_handle - handle_ > @history_size
|
129
|
-
File.delete("#{@normal_path}.#{@preferred_handle-handle_-1}") rescue nil
|
129
|
+
::File.delete("#{@normal_path}.#{@preferred_handle-handle_-1}") rescue nil
|
130
130
|
end
|
131
131
|
@open_handles.delete(handle_)
|
132
132
|
nil
|
@@ -138,22 +138,22 @@ module Sawmill
|
|
138
138
|
def before_write
|
139
139
|
return unless @max_logfile_size || @shift_period
|
140
140
|
turnover_ = false
|
141
|
-
if @max_logfile_size && File.file?(@normal_path) && File.size(@normal_path) > @max_logfile_size
|
141
|
+
if @max_logfile_size && ::File.file?(@normal_path) && ::File.size(@normal_path) > @max_logfile_size
|
142
142
|
turnover_ = true
|
143
143
|
end
|
144
|
-
if @shift_period && (Time.now - @last_shift) > @shift_period
|
144
|
+
if @shift_period && (::Time.now - @last_shift) > @shift_period
|
145
145
|
turnover_ = true
|
146
146
|
end
|
147
147
|
if turnover_
|
148
148
|
max_ = @preferred_handle - @open_handles.keys.min + 1
|
149
149
|
max_ = @history_size if max_ < @history_size
|
150
|
-
File.delete("#{@normal_path}.#{max_-1}") rescue nil
|
150
|
+
::File.delete("#{@normal_path}.#{max_-1}") rescue nil
|
151
151
|
(max_-1).downto(1) do |index_|
|
152
|
-
File.rename("#{@normal_path}.#{index_-1}", "#{@normal_path}.#{index_}") rescue nil
|
152
|
+
::File.rename("#{@normal_path}.#{index_-1}", "#{@normal_path}.#{index_}") rescue nil
|
153
153
|
end
|
154
|
-
File.rename("#{@normal_path}", "#{@normal_path}.0") rescue nil
|
154
|
+
::File.rename("#{@normal_path}", "#{@normal_path}.0") rescue nil
|
155
155
|
@preferred_handle += 1
|
156
|
-
@last_shift = Time.now
|
156
|
+
@last_shift = ::Time.now
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
data/lib/sawmill/rotater.rb
CHANGED
@@ -73,13 +73,13 @@ module Sawmill
|
|
73
73
|
|
74
74
|
def initialize(io_manager_, opts_={})
|
75
75
|
@omit_directives = opts_.delete(:omit_directives)
|
76
|
-
if io_manager_.kind_of?(Class)
|
76
|
+
if io_manager_.kind_of?(::Class)
|
77
77
|
@io_manager = io_manager_.new(opts_)
|
78
78
|
else
|
79
79
|
@io_manager = io_manager_
|
80
80
|
end
|
81
81
|
@handles ||= {}
|
82
|
-
@mutex ||= Monitor.new
|
82
|
+
@mutex ||= ::Monitor.new
|
83
83
|
end
|
84
84
|
|
85
85
|
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill heap 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
|
+
module Util
|
40
|
+
|
41
|
+
|
42
|
+
# A simple heap class.
|
43
|
+
|
44
|
+
class Heap
|
45
|
+
|
46
|
+
|
47
|
+
# Create a new heap.
|
48
|
+
|
49
|
+
def initialize(data_=nil, &block_)
|
50
|
+
@_heap = data_ || []
|
51
|
+
@_comparator = block_ || ::Proc.new{ |a_,b_| a_ <=> b_ }
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def merge(enum_)
|
56
|
+
enum_.each{ |value_| add(value_) }
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def add(value_)
|
62
|
+
@_heap << value_
|
63
|
+
_sift_up(@_heap.length-1)
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def <<(value_)
|
69
|
+
add(value_)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def remove
|
74
|
+
ret_ = @_heap[0]
|
75
|
+
if @_heap.length > 1
|
76
|
+
@_heap[0] = @_heap.pop
|
77
|
+
_sift_down(0)
|
78
|
+
else
|
79
|
+
@_heap.clear
|
80
|
+
end
|
81
|
+
ret_
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def peek
|
86
|
+
@_heap[0]
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def size
|
91
|
+
@_heap.size
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def empty?
|
96
|
+
@_heap.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def clear
|
101
|
+
@_heap.clear
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def each!
|
106
|
+
while !empty?
|
107
|
+
yield(remove)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def _sift_up(start_) # :nodoc:
|
115
|
+
while start_ > 0
|
116
|
+
parent_ = (start_ + 1) / 2 - 1
|
117
|
+
if @_comparator.call(@_heap[start_], @_heap[parent_]) < 0
|
118
|
+
@_heap[start_], @_heap[parent_] = @_heap[parent_], @_heap[start_]
|
119
|
+
start_ = parent_
|
120
|
+
else
|
121
|
+
return start_
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def _sift_down(start_) # :nodoc:
|
128
|
+
length_ = self.size
|
129
|
+
while length_ >= (child2_ = (start_ + 1) * 2)
|
130
|
+
child1_ = child2_-1
|
131
|
+
if length_ <= child2_
|
132
|
+
earliest_child_ = child1_
|
133
|
+
elsif @_comparator.call(@_heap[child1_], @_heap[child2_]) < 0
|
134
|
+
earliest_child_ = child1_
|
135
|
+
else
|
136
|
+
earliest_child_ = child2_
|
137
|
+
end
|
138
|
+
if @_comparator.call(@_heap[start_], @_heap[earliest_child_]) < 0
|
139
|
+
return start_
|
140
|
+
else
|
141
|
+
@_heap[start_], @_heap[earliest_child_] = @_heap[earliest_child_], @_heap[start_]
|
142
|
+
start_ = earliest_child_
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
data/lib/sawmill/util/queue.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
#
|
3
|
-
# Sawmill
|
3
|
+
# Sawmill queue utility
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2009 Daniel Azuma
|
@@ -101,6 +101,7 @@ module Sawmill
|
|
101
101
|
if @push_ptr
|
102
102
|
if @pop_ptr
|
103
103
|
object_ = @buffer[@pop_ptr]
|
104
|
+
@buffer[@pop_ptr] = nil
|
104
105
|
@pop_ptr += 1
|
105
106
|
@pop_ptr = 0 if @pop_ptr == @buffer.size
|
106
107
|
@pop_ptr = nil if @pop_ptr == @push_ptr
|
@@ -114,6 +115,31 @@ module Sawmill
|
|
114
115
|
end
|
115
116
|
|
116
117
|
|
118
|
+
# Return an array of the contents of the queue, in order.
|
119
|
+
|
120
|
+
def dequeue_all
|
121
|
+
if @push_ptr
|
122
|
+
if @pop_ptr
|
123
|
+
if @pop_ptr < @push_ptr
|
124
|
+
ret_ = @buffer[@pop_ptr..@push_ptr-1]
|
125
|
+
else
|
126
|
+
ret_ = @buffer[@pop_ptr..-1] + @buffer[0..@push_ptr-1]
|
127
|
+
end
|
128
|
+
@buffer.fill(nil)
|
129
|
+
@push_ptr = 0
|
130
|
+
@pop_ptr = nil
|
131
|
+
ret_
|
132
|
+
else
|
133
|
+
[]
|
134
|
+
end
|
135
|
+
else
|
136
|
+
ret_ = @buffer
|
137
|
+
@buffer = []
|
138
|
+
ret_
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
117
143
|
# Return the size of the queue, which is 0 if the queue is empty.
|
118
144
|
|
119
145
|
def size
|
data/lib/sawmill/version.rb
CHANGED
data/lib/sawmill.rb
CHANGED
@@ -49,6 +49,7 @@ dir_ = ::File.expand_path('sawmill', ::File.dirname(__FILE__))
|
|
49
49
|
includes_ = [
|
50
50
|
'version',
|
51
51
|
'util/queue',
|
52
|
+
'util/heap',
|
52
53
|
'errors',
|
53
54
|
'level',
|
54
55
|
'entry',
|
@@ -68,6 +69,7 @@ includes_ = [
|
|
68
69
|
'record_processor/decompose',
|
69
70
|
'record_processor/format',
|
70
71
|
'parser',
|
72
|
+
'multi_parser',
|
71
73
|
'logger',
|
72
74
|
'rotater',
|
73
75
|
'rotater/base',
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Sawmill: tests multi-parser
|
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 'test/unit'
|
37
|
+
require 'stringio'
|
38
|
+
require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
|
39
|
+
|
40
|
+
|
41
|
+
module Sawmill
|
42
|
+
module Tests # :nodoc:
|
43
|
+
|
44
|
+
class TestMultiParser < ::Test::Unit::TestCase # :nodoc:
|
45
|
+
|
46
|
+
|
47
|
+
def setup
|
48
|
+
@levels = ::Sawmill::STANDARD_LEVELS
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def _get_io_array(entry_groups_)
|
53
|
+
strings_ = []
|
54
|
+
entry_groups_.each do |entries_|
|
55
|
+
stringio_ = ::StringIO.new
|
56
|
+
formatter_ = ::Sawmill::EntryClassifier.new(::Sawmill::Formatter.new(stringio_, :fractional_second_digits => 6))
|
57
|
+
entries_.each do |entry_|
|
58
|
+
formatter_.entry(entry_)
|
59
|
+
end
|
60
|
+
strings_ << stringio_.string
|
61
|
+
end
|
62
|
+
strings_.map{ |str_| ::StringIO.new(str_) }
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Test interleaved entries including unknown data entries.
|
67
|
+
# Makes sure they come out in the right order.
|
68
|
+
|
69
|
+
def test_interleaved_entries
|
70
|
+
base_time_ = Time.now.utc
|
71
|
+
entries_ = []
|
72
|
+
2.times do |i_|
|
73
|
+
entries_ << ::Sawmill::Entry::UnknownData.new("Unknown #{i_}")
|
74
|
+
end
|
75
|
+
4.times do |i_|
|
76
|
+
entries_ << ::Sawmill::Entry::Message.new(@levels.get(:INFO), base_time_+i_, 'rails', nil, "Hello #{i_}")
|
77
|
+
end
|
78
|
+
io_array_ = _get_io_array([[entries_[0], entries_[2], entries_[5]], [entries_[3], entries_[4], entries_[1]]])
|
79
|
+
queue_ = ::Sawmill::EntryProcessor::SimpleQueue.new
|
80
|
+
::Sawmill::MultiParser.new(io_array_, queue_).parse_all
|
81
|
+
assert_equal([entries_[0], entries_[2], entries_[3], entries_[4], entries_[1], entries_[5]], queue_.dequeue_all)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sawmill
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.2.
|
23
|
+
version: 0.2.2
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: versionomy
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.1.
|
33
|
+
version: 0.1.2
|
34
34
|
version:
|
35
35
|
description: Sawmill is a logging and log analysis system for Ruby. It extends the basic Ruby logging facility with log records and parsing abilities.
|
36
36
|
email: dazuma@gmail.com
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/sawmill/level.rb
|
55
55
|
- lib/sawmill/log_record_middleware.rb
|
56
56
|
- lib/sawmill/logger.rb
|
57
|
+
- lib/sawmill/multi_parser.rb
|
57
58
|
- lib/sawmill/parser.rb
|
58
59
|
- lib/sawmill/record.rb
|
59
60
|
- lib/sawmill/record_processor/conditionals.rb
|
@@ -67,6 +68,7 @@ files:
|
|
67
68
|
- lib/sawmill/rotater/date_based_log_file.rb
|
68
69
|
- lib/sawmill/rotater/shifting_log_file.rb
|
69
70
|
- lib/sawmill/rotater.rb
|
71
|
+
- lib/sawmill/util/heap.rb
|
70
72
|
- lib/sawmill/util/queue.rb
|
71
73
|
- lib/sawmill/version.rb
|
72
74
|
- lib/sawmill.rb
|
@@ -74,13 +76,14 @@ files:
|
|
74
76
|
- tests/tc_formatter_parser.rb
|
75
77
|
- tests/tc_levels.rb
|
76
78
|
- tests/tc_logger.rb
|
79
|
+
- tests/tc_multi_parser.rb
|
77
80
|
- tests/tc_record_processors.rb
|
78
81
|
- tests/tc_records.rb
|
79
82
|
- History.rdoc
|
80
83
|
- README.rdoc
|
81
84
|
- Rakefile
|
82
85
|
has_rdoc: true
|
83
|
-
homepage: http://
|
86
|
+
homepage: http://virtuoso.rubyforge.org/sawmill
|
84
87
|
licenses: []
|
85
88
|
|
86
89
|
post_install_message:
|
@@ -112,5 +115,6 @@ test_files:
|
|
112
115
|
- tests/tc_formatter_parser.rb
|
113
116
|
- tests/tc_levels.rb
|
114
117
|
- tests/tc_logger.rb
|
118
|
+
- tests/tc_multi_parser.rb
|
115
119
|
- tests/tc_record_processors.rb
|
116
120
|
- tests/tc_records.rb
|