sawmill 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,11 @@
1
- === 0.0.4 / 2009-??-??
1
+ === 0.0.5 / 2009-11-08
2
+
3
+ * API CHANGE: Reworked how string encoding is specified. Default encoding for both reading and writing is now ASCII-8BIT unless specified in the API or within the file as a parser directive.
4
+ * Handle encoding errors more gracefully by replacing characters rather than raising exceptions.
5
+ * Added a parser directive to set logfile encoding.
6
+ * Versionomy is no longer a hard dependency-- it is now used only if available.
7
+
8
+ === 0.0.4 / 2009-11-06
2
9
 
3
10
  * API CHANGE: Renamed DateBasedLogFile options :prefix and :suffix to :path_prefix and :path_suffix
4
11
  * API CHANGE: Renamed ShiftingLogFile options :filepath and :max_logfile_size to :file_path and :max_file_size
@@ -26,7 +26,7 @@ Sawmill is an extension to the standard ruby Logger mechanism that enables autom
26
26
  === Requirements
27
27
 
28
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.
29
+ * Blockenspiel 0.3.1 or later.
30
30
 
31
31
  === Installation
32
32
 
data/Rakefile CHANGED
@@ -88,8 +88,7 @@ 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.3.0')
92
- s_.add_dependency('versionomy', '>= 0.2.0')
91
+ s_.add_dependency('blockenspiel', '>= 0.3.1')
93
92
  end
94
93
  ::Rake::GemPackageTask.new(gemspec_) do |task_|
95
94
  task_.need_zip = false
@@ -34,14 +34,7 @@
34
34
  ;
35
35
 
36
36
 
37
- begin
38
- require 'blockenspiel'
39
- require 'versionomy'
40
- rescue ::LoadError
41
- require 'rubygems'
42
- require 'blockenspiel'
43
- require 'versionomy'
44
- end
37
+ require 'blockenspiel'
45
38
 
46
39
 
47
40
  dir_ = ::File.expand_path('sawmill', ::File.dirname(__FILE__))
@@ -266,11 +266,13 @@ module Sawmill
266
266
  # <tt>:encoding</tt>::
267
267
  # Specify an encoding for file data. (Ruby 1.9 only.)
268
268
  # You may specify an encoding name or an encoding object.
269
- # If not specified, uses the default external encoding.
269
+ # If not specified, reads raw bytes (e.g. defaults to 'ASCII-8BIT').
270
+ # Note that the encoding may also be modified by the file itself,
271
+ # if an appropriate parser directive is encountered.
270
272
  # <tt>:internal_encoding</tt>::
271
273
  # Specify an encoding to transcode to. (Ruby 1.9 only.)
272
274
  # You may specify an encoding name or an encoding object.
273
- # If not specified, uses the default internal encoding.
275
+ # If not specified, uses the encoding as read from the file.
274
276
 
275
277
  def open_entries(globs_, opts_={}, &block_)
276
278
  processor_ = EntryProcessor.build(&block_)
@@ -297,11 +299,13 @@ module Sawmill
297
299
  # <tt>:encoding</tt>::
298
300
  # Specify an encoding for file data. (Ruby 1.9 only.)
299
301
  # You may specify an encoding name or an encoding object.
300
- # If not specified, uses the default external encoding.
302
+ # If not specified, reads raw bytes (e.g. defaults to 'ASCII-8BIT').
303
+ # Note that the encoding may also be modified by the file itself,
304
+ # if an appropriate parser directive is encountered.
301
305
  # <tt>:internal_encoding</tt>::
302
306
  # Specify an encoding to transcode to. (Ruby 1.9 only.)
303
307
  # You may specify an encoding name or an encoding object.
304
- # If not specified, uses the default internal encoding.
308
+ # If not specified, uses the encoding as read from the file.
305
309
 
306
310
  def open_records(globs_, opts_={}, &block_)
307
311
  processor_ = RecordProcessor.build(&block_)
@@ -331,11 +335,13 @@ module Sawmill
331
335
  # <tt>:encoding</tt>::
332
336
  # Specify an encoding for file data. (Ruby 1.9 only.)
333
337
  # You may specify an encoding name or an encoding object.
334
- # If not specified, uses the default external encoding.
338
+ # If not specified, reads raw bytes (e.g. defaults to 'ASCII-8BIT').
339
+ # Note that the encoding may also be modified by the file itself,
340
+ # if an appropriate parser directive is encountered.
335
341
  # <tt>:internal_encoding</tt>::
336
342
  # Specify an encoding to transcode to. (Ruby 1.9 only.)
337
343
  # You may specify an encoding name or an encoding object.
338
- # If not specified, uses the default internal encoding.
344
+ # If not specified, uses the encoding as read from the file.
339
345
 
340
346
  def open_files(globs_, processor_, opts_={})
341
347
  finish_opt_ = opts_.delete(:finish)
@@ -343,20 +349,17 @@ module Sawmill
343
349
  internal_encoding_ = opts_.delete(:internal_encoding)
344
350
  mode_ = 'r'
345
351
  if defined?(::Encoding)
346
- if encoding_
347
- encoding_ = ::Encoding.find(encoding_) unless encoding_.respond_to?(:name)
348
- encoding_ = nil if encoding_ == ::Encoding.default_external
352
+ if !encoding_
353
+ encoding_ = ::Encoding::ASCII_8BIT
354
+ elsif encoding_ && !encoding_.respond_to?(:name)
355
+ encoding_ = ::Encoding.find(encoding_)
349
356
  end
350
- if internal_encoding_
351
- internal_encoding_ = ::Encoding.find(internal_encoding_) unless internal_encoding_.respond_to?(:name)
352
- internal_encoding_ = nil if internal_encoding_ == ::Encoding.default_internal
357
+ if internal_encoding_ && !internal_encoding_.respond_to?(:name)
358
+ internal_encoding_ = ::Encoding.find(internal_encoding_)
353
359
  end
354
360
  if encoding_
355
361
  mode_ << ":#{encoding_.name}"
356
- elsif internal_encoding_
357
- mode_ << ":#{::Encoding.default_external.name}"
358
362
  end
359
- mode_ << ":#{internal_encoding_.name}" if internal_encoding_
360
363
  else
361
364
  encoding_ = nil
362
365
  internal_encoding_ = nil
@@ -376,7 +379,7 @@ module Sawmill
376
379
  else
377
380
  io_array_ << ::File.open(path_, mode_)
378
381
  encoding_array_ << nil
379
- internal_encoding_array_ << nil
382
+ internal_encoding_array_ << internal_encoding_
380
383
  end
381
384
  end
382
385
  end
@@ -46,6 +46,8 @@ module Sawmill
46
46
  LINE_REGEXP = /^\[\s*([[:graph:]]+)\s+(\d{4})-(\d{2})-(\d{2})(T|\s)(\d{2}):(\d{2}):(\d{2})(.(\d{1,6}))?Z?\s?([+-]\d{4})?\s+([[:graph:]]+)(\s+([[:graph:]]+))?\s+([\^$.=])\]\s(.*)$/
47
47
  DIRECTIVE_REGEXP = /^#\s+sawmill_format:\s+(\w+)=(.*)$/
48
48
  ATTRIBUTE_REGEXP = /^([[:graph:]]+)\s([=+\/-])\s/
49
+ SUPPORTS_ENCODING = defined?(::Encoding)
50
+ ENCODING_OPTS = {:invalid => :replace, :undef => :replace}
49
51
  # :startdoc:
50
52
 
51
53
 
@@ -65,6 +67,16 @@ module Sawmill
65
67
  # <tt>:emit_incomplete_records_at_eof</tt>
66
68
  # If set to true, causes any incomplete log records to be emitted
67
69
  # in their incomplete state when EOF is reached.
70
+ # <tt>:encoding</tt>
71
+ # Overrides the IO encoding. (Ruby 1.9 only). If specified, lines
72
+ # read from the stream are assumed to be in this encoding. If not
73
+ # specified, the IO's default encoding is honored.
74
+ # Note that the encoding may also be modified by the stream itself,
75
+ # if an appropriate parser directive is encountered.
76
+ # <tt>:internal_encoding</tt>
77
+ # Transcodes strings as they are read. (Ruby 1.9 only). If specified,
78
+ # lines are transcoded into this encoding after they are read from
79
+ # the stream. If not specified, no post-transcoding is done.
68
80
 
69
81
  def initialize(io_, processor_, opts_={})
70
82
  @io = io_
@@ -77,11 +89,10 @@ module Sawmill
77
89
  @levels = opts_[:levels] || STANDARD_LEVELS
78
90
  @emit_incomplete_records_at_eof = opts_[:emit_incomplete_records_at_eof]
79
91
  @current_record_id = nil
80
- @parser_directives = {}
81
- @encoding = opts_[:encoding]
82
- @internal_encoding = opts_[:internal_encoding]
83
- if defined?(::Encoding)
92
+ if SUPPORTS_ENCODING
93
+ @encoding = opts_[:encoding]
84
94
  @encoding = ::Encoding.find(@encoding) if @encoding && !@encoding.kind_of?(::Encoding)
95
+ @internal_encoding = opts_[:internal_encoding]
85
96
  @internal_encoding = ::Encoding.find(@internal_encoding) if @internal_encoding && !@internal_encoding.kind_of?(::Encoding)
86
97
  end
87
98
  end
@@ -158,7 +169,7 @@ module Sawmill
158
169
  end
159
170
  else
160
171
  if str_ =~ DIRECTIVE_REGEXP
161
- @parser_directives[$1] = $2
172
+ _set_parser_directive($1, $2)
162
173
  end
163
174
  entry_ = Entry::UnknownData.new(str_.chomp)
164
175
  @processor.unknown_data(entry_) if @processor.respond_to?(:unknown_data)
@@ -185,14 +196,25 @@ module Sawmill
185
196
 
186
197
  def _get_next_line # :nodoc:
187
198
  str_ = @io.gets
188
- if str_
199
+ if str_ && SUPPORTS_ENCODING
189
200
  str_.force_encoding(@encoding) if @encoding
190
- str_.encode!(@internal_encoding) if @internal_encoding
201
+ str_.encode!(@internal_encoding, ENCODING_OPTS) if @internal_encoding
191
202
  end
192
203
  str_
193
204
  end
194
205
 
195
206
 
207
+ def _set_parser_directive(key_, value_) # :nodoc:
208
+ case key_
209
+ when 'encoding'
210
+ if SUPPORTS_ENCODING
211
+ encoding_ = ::Encoding.find(value_) rescue nil
212
+ @encoding = encoding_ if encoding_
213
+ end
214
+ end
215
+ end
216
+
217
+
196
218
  end
197
219
 
198
220
 
@@ -59,6 +59,11 @@ module Sawmill
59
59
 
60
60
  class Rotater
61
61
 
62
+ # :stopdoc:
63
+ SUPPORTS_ENCODING = defined?(::Encoding)
64
+ ENCODING_OPTS = {:invalid => :replace, :undef => :replace}
65
+ # :startdoc:
66
+
62
67
 
63
68
  # Create a rotater using the given rotation strategy.
64
69
  # See Sawmill::Rotater::DateBasedLogFile and
@@ -70,9 +75,26 @@ module Sawmill
70
75
  #
71
76
  # <tt>:omit_directives</tt>::
72
77
  # If true, omit standard logfile directives. Default is false.
78
+ # <tt>:concurrent_writes</tt>::
79
+ # Set this to true if you expect multiple processes to attempt to
80
+ # write to the same log file simultaneously. This option causes the
81
+ # rotater to surround writes with an acquisition of the cooperative
82
+ # filesystem lock (if available) for the logfile, in an attempt to
83
+ # prevent lines from interleaving in one another. Default is false.
84
+ # <tt>:encoding</tt>::
85
+ # Specify an encoding for file data. (Ruby 1.9 only).
86
+ # You may pass either an encoding object or an encoding name.
87
+ # If not specified, writes raw bytes (e.g. defaults to ASCII-8BIT).
73
88
 
74
89
  def initialize(io_manager_, opts_={})
75
90
  @omit_directives = opts_.delete(:omit_directives)
91
+ @concurrent_writes = opts_.delete(:concurrent_writes)
92
+ if SUPPORTS_ENCODING
93
+ @encoding = opts_.delete(:encoding)
94
+ if @encoding && !@encoding.respond_to?(:name)
95
+ @encoding = ::Encoding.find(@encoding)
96
+ end
97
+ end
76
98
  if io_manager_.kind_of?(::Class)
77
99
  @io_manager = io_manager_.new(opts_)
78
100
  else
@@ -99,6 +121,23 @@ module Sawmill
99
121
  end
100
122
 
101
123
 
124
+ def _write_to_stream(io_, str_)
125
+ if SUPPORTS_ENCODING && @encoding
126
+ str_ = str_.encode(@encoding, ENCODING_OPTS)
127
+ end
128
+ if @concurrent_writes
129
+ begin
130
+ io_.flock(::File::LOCK_EX)
131
+ io_.write(str_)
132
+ ensure
133
+ io_.flock(::File::LOCK_UN)
134
+ end
135
+ else
136
+ io_.write(str_)
137
+ end
138
+ end
139
+
140
+
102
141
  def _obtain_handle # :nodoc:
103
142
  handle_ = @io_manager.preferred_handle
104
143
  if @handles.include?(handle_)
@@ -106,7 +145,13 @@ module Sawmill
106
145
  else
107
146
  io_ = @io_manager.open_handle(handle_)
108
147
  unless @omit_directives
109
- io_.write("# sawmill_format: version=1\n")
148
+ _write_to_stream(io_, "# sawmill_format: version=1\n")
149
+ if defined?(::Encoding)
150
+ encoding_ = io_.encoding
151
+ if encoding_
152
+ _write_to_stream(io_, "# sawmill_format: encoding=#{encoding_.name}\n")
153
+ end
154
+ end
110
155
  end
111
156
  @handles[handle_] = [handle_, io_, 1]
112
157
  end
@@ -149,7 +194,7 @@ module Sawmill
149
194
  handle_ = _check_rotate_handle(handle_)
150
195
  end
151
196
  info_ = @handles[handle_]
152
- info_[1].write(str_)
197
+ _write_to_stream(info_[1], str_)
153
198
  handle_
154
199
  end
155
200
  end
@@ -79,9 +79,6 @@ module Sawmill
79
79
  # <tt>:local_datestamps</tt>::
80
80
  # If true, use the local timezone to create datestamps.
81
81
  # The default is to use UTC.
82
- # <tt>:encoding</tt>::
83
- # Specify an encoding name for file data. (Ruby 1.9 only)
84
- # If not specified, uses the default external encoding.
85
82
 
86
83
  def initialize(options_)
87
84
  @turnover_frequency = options_[:turnover_frequency] || :none
@@ -97,10 +94,6 @@ module Sawmill
97
94
  when :hourly then "%Y-%m-%d-%H"
98
95
  else nil
99
96
  end
100
- @mode = 'a'
101
- if defined?(::Encoding) && (encoding_ = options_[:encoding])
102
- @mode << ":#{encoding_}"
103
- end
104
97
  end
105
98
 
106
99
 
@@ -125,7 +118,7 @@ module Sawmill
125
118
  else
126
119
  path_ = @prefix+@suffix
127
120
  end
128
- file_ = ::File.open(path_, @mode)
121
+ file_ = ::File.open(path_, 'a')
129
122
  file_.sync = true
130
123
  file_
131
124
  end
@@ -76,9 +76,6 @@ module Sawmill
76
76
  # The maximum number of old logfiles (files with indexes) to
77
77
  # keep. Files beyond this history size will be automatically
78
78
  # deleted. Default is 1. This value must be at least 1.
79
- # <tt>:encoding</tt>::
80
- # Specify an encoding name for file data. (Ruby 1.9 only)
81
- # If not specified, uses the default external encoding.
82
79
 
83
80
  def initialize(options_)
84
81
  @max_logfile_size = options_[:max_file_size] || options_[:max_logfile_size]
@@ -100,10 +97,6 @@ module Sawmill
100
97
  @preferred_handle = 0
101
98
  @open_handles = {}
102
99
  @last_shift = ::Time.now
103
- @mode = 'a'
104
- if defined?(::Encoding) && (encoding_ = options_[:encoding])
105
- @mode << ":#{encoding_}"
106
- end
107
100
  end
108
101
 
109
102
 
@@ -122,7 +115,7 @@ module Sawmill
122
115
  else
123
116
  path_ = "#{@normal_path}.#{@preferred_handle-handle_-1}"
124
117
  end
125
- file_ = ::File.open(path_, @mode)
118
+ file_ = ::File.open(path_, 'a')
126
119
  file_.sync = true
127
120
  @open_handles[handle_] = true
128
121
  file_
@@ -34,12 +34,19 @@
34
34
  ;
35
35
 
36
36
 
37
+ begin
38
+ require 'versionomy'
39
+ rescue ::LoadError
40
+ end
41
+
42
+
37
43
  module Sawmill
38
44
 
39
45
  # Current gem version, as a frozen string.
40
- VERSION_STRING = '0.0.4'.freeze
46
+ VERSION_STRING = '0.0.5'.freeze
41
47
 
42
- # Current gem version, as a Versionomy::Value.
43
- VERSION = ::Versionomy.parse(VERSION_STRING, :standard)
48
+ # Current gem version, as a Versionomy::Value if the versionomy library
49
+ # is available, or as a frozen string if not.
50
+ VERSION = defined?(::Versionomy) ? ::Versionomy.parse(VERSION_STRING, :standard) : VERSION_STRING
44
51
 
45
52
  end
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
38
39
 
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require 'stringio'
38
39
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require 'logger'
38
39
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
38
39
 
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require 'stringio'
38
39
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
38
39
 
@@ -33,7 +33,9 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
38
+ require 'set'
37
39
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
38
40
 
39
41
 
@@ -108,7 +110,7 @@ module Sawmill
108
110
  record_ = @records.dequeue
109
111
  assert_equal(0, record_.message_count)
110
112
  assert_equal(5, record_.entry_count)
111
- assert_equal(Set.new(['color', 'size']), Set.new(record_.attribute_keys))
113
+ assert_equal(::Set.new(['color', 'size']), ::Set.new(record_.attribute_keys))
112
114
  assert_equal('small', record_.attribute('size'))
113
115
  assert_equal('red', record_.attribute('color'))
114
116
  end
@@ -125,7 +127,7 @@ module Sawmill
125
127
  record_ = @records.dequeue
126
128
  assert_equal(0, record_.message_count)
127
129
  assert_equal(5, record_.entry_count)
128
- assert_equal(Set.new(['color', 'size']), Set.new(record_.attribute_keys))
130
+ assert_equal(::Set.new(['color', 'size']), ::Set.new(record_.attribute_keys))
129
131
  assert_equal(['small'], record_.attribute('size'))
130
132
  assert_equal(['blue', 'red'], record_.attribute('color'))
131
133
  end
@@ -33,6 +33,7 @@
33
33
  # -----------------------------------------------------------------------------
34
34
 
35
35
 
36
+ require 'rubygems'
36
37
  require 'test/unit'
37
38
  require 'stringio'
38
39
  require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/sawmill.rb")
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
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-06 00:00:00 -08:00
12
+ date: 2009-11-08 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,17 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.3.0
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: versionomy
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 0.2.0
23
+ version: 0.3.1
34
24
  version:
35
25
  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
26
  email: dazuma@gmail.com