sawmill 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc CHANGED
@@ -1,3 +1,13 @@
1
+ === 0.1.12 / 2010-11-01
2
+
3
+ * A date-based rotater can now force log files to be written to by only one process. Useful in environments where you have an unknown number of processes(i.e. a Passenger-based deployment), each of which needs a separate log file.
4
+ * Provided a Railtie for easy integration into a Rails 3 application.
5
+ * The record_progname and attribute_level can now be set on a logger after creation.
6
+
7
+ === 0.1.11 / 2010-10-19
8
+
9
+ * Fixed a missing require.
10
+
1
11
  === 0.0.10 / 2010-01-31
2
12
 
3
13
  * Fixed a rotater issue that sometimes caused rotation to occur one record too late.
data/README.rdoc CHANGED
@@ -22,11 +22,12 @@ Sawmill is an extension to the standard ruby Logger mechanism that enables autom
22
22
  * Parse logfiles back into log entries and log records
23
23
  * Log analysis framework
24
24
  * Rack middleware for quick setup of web service logs
25
+ * Railtie for Rails 3 integration
25
26
 
26
27
  === Requirements
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
- * Blockenspiel 0.3.1 or later.
29
+ * Ruby 1.8.7 or later (Ruby 1.9.2 or later recommended), or JRuby 1.4 or later.
30
+ * Blockenspiel 0.4.1 or later.
30
31
 
31
32
  === Installation
32
33
 
@@ -48,11 +49,13 @@ Contact the author at dazuma at gmail dot com.
48
49
 
49
50
  === Author / Credits
50
51
 
51
- Lumber is written by Daniel Azuma (http://www.daniel-azuma.com/).
52
+ Sawmill is written by Daniel Azuma (http://www.daniel-azuma.com/).
52
53
 
53
- == LICENSE:
54
+ Development of Sawmill is sponsored by GeoPage (http://www.geopage.com/).
54
55
 
55
- Copyright 2009 Daniel Azuma.
56
+ === License
57
+
58
+ Copyright 2009-2010 Daniel Azuma.
56
59
 
57
60
  All rights reserved.
58
61
 
data/Version CHANGED
@@ -1 +1 @@
1
- 0.1.11
1
+ 0.1.12
@@ -67,6 +67,12 @@ module Sawmill
67
67
  end
68
68
 
69
69
 
70
+ # Could not open a log file because a uniquifier failed.
71
+
72
+ class NoUniqueLogFileError < SawmillError
73
+ end
74
+
75
+
70
76
  end
71
77
 
72
78
 
@@ -34,10 +34,7 @@
34
34
  ;
35
35
 
36
36
 
37
- begin
38
- require 'securerandom'
39
- rescue ::LoadError
40
- end
37
+ require 'securerandom'
41
38
 
42
39
 
43
40
  module Sawmill
@@ -254,6 +251,20 @@ module Sawmill
254
251
  end
255
252
 
256
253
 
254
+ # Get the current record progname setting for this logger
255
+
256
+ def record_progname
257
+ @record_progname
258
+ end
259
+
260
+
261
+ # Set the current record progname setting for this logger
262
+
263
+ def record_progname=(value_)
264
+ @record_progname = value_.to_s.gsub(/\s+/, '')
265
+ end
266
+
267
+
257
268
  # Get the current level setting for this logger as a Sawmill::Level.
258
269
 
259
270
  def level
@@ -282,6 +293,32 @@ module Sawmill
282
293
  alias_method :sev_threshold, :level
283
294
 
284
295
 
296
+ # Get the current attribute level setting for this logger as a
297
+ # Sawmill::Level.
298
+
299
+ def attribute_level
300
+ @attribute_level
301
+ end
302
+
303
+
304
+ # Set the current attribute level setting for this logger.
305
+ # You may specify the level as a string, a symbol, an integer, or a
306
+ # Sawmill::Level. Ruby's logger constants such as ::Logger::INFO
307
+ # will also work.
308
+
309
+ def attribute_level=(value_)
310
+ if value_.kind_of?(Level)
311
+ @attribute_level = value_
312
+ else
313
+ level_obj_ = @level_group.get(value_)
314
+ if level_obj_.nil?
315
+ raise Errors::UnknownLevelError, value_
316
+ end
317
+ @attribute_level = level_obj_
318
+ end
319
+ end
320
+
321
+
285
322
  # Get the LevelGroup in use by this Logger. This setting cannot be
286
323
  # changed once the logger is constructed.
287
324
 
@@ -348,32 +385,16 @@ module Sawmill
348
385
 
349
386
 
350
387
  def self._get_default_record_id_generator # :nodoc:
351
- unless @_default_generator
352
- if defined?(::SecureRandom)
353
- _random_hex32 = ::Proc.new do
354
- ::SecureRandom.hex(16)
355
- end
356
- elsif defined?(::ActiveSupport::SecureRandom)
357
- _random_hex32 = ::Proc.new do
358
- ::ActiveSupport::SecureRandom.hex(16)
359
- end
360
- else
361
- _random_hex32 = ::Proc.new do
362
- ::Kernel.rand(0x100000000000000000000000000000000).to_s(16).rjust(32, '0')
363
- end
364
- end
365
- @_default_generator = ::Proc.new do
366
- uuid_ = _random_hex32.call
367
- uuid_[12] = '4'
368
- uuid_[16] = (uuid_[16,1].to_i(16)&3|8).to_s(16)
369
- uuid_.insert(8, '-')
370
- uuid_.insert(13, '-')
371
- uuid_.insert(18, '-')
372
- uuid_.insert(23, '-')
373
- uuid_
374
- end
388
+ @_default_generator ||= ::Proc.new do
389
+ uuid_ = ::SecureRandom.hex(16)
390
+ uuid_[12] = '4'
391
+ uuid_[16] = (uuid_[16,1].to_i(16)&3|8).to_s(16)
392
+ uuid_.insert(8, '-')
393
+ uuid_.insert(13, '-')
394
+ uuid_.insert(18, '-')
395
+ uuid_.insert(23, '-')
396
+ uuid_
375
397
  end
376
- @_default_generator
377
398
  end
378
399
 
379
400
 
@@ -0,0 +1,153 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Sawmill railtie
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
+ require 'sawmill'
38
+ require 'rails/railtie'
39
+
40
+
41
+ module Sawmill
42
+
43
+
44
+ # Railtie that replaces the default Rails logger with a Sawmill logger.
45
+ # Sets the Rails logger to a Sawmill::Logger, and installs a
46
+ # Sawmill::LogRecordMiddleware to enable record-based logging.
47
+ #
48
+ # To install into a Rails app, include this line in your
49
+ # config/application.rb:
50
+ # require 'sawmill/railtie'
51
+ # It should appear before your application configuration.
52
+ #
53
+ # You can then configure sawmill using the standard rails configuration
54
+ # mechanism. The sawmill configuration lives in the config.sawmill
55
+ # configuration namespace. See Sawmill::Railtie::Configuration for the
56
+ # configuration options.
57
+
58
+ class Railtie < ::Rails::Railtie
59
+
60
+
61
+ # Configuration options. These are attributes of config.sawmill.
62
+
63
+ class Configuration
64
+
65
+ def initialize # :nodoc:
66
+ @logfile = ::STDERR
67
+ @formatter_options = {}
68
+ @logger_options = {}
69
+ @include_id = false
70
+ @fractional_second_digits = 2
71
+ @level_width = nil
72
+ @local_time = false
73
+ @iso_8601_time = false
74
+ @length_limit = nil
75
+ @level = :INFO
76
+ @attribute_level = nil
77
+ @progname = 'rails'
78
+ @record_progname = nil
79
+ @record_id_generator = nil
80
+ @request_id_key = 'sawmill.request_id'
81
+ @start_time_attribute = nil
82
+ @end_time_attribute = nil
83
+ end
84
+
85
+ # The log file to write to. This should be either an IO object, or
86
+ # a Sawmill::Rotater. Default is STDERR.
87
+ attr_accessor :logfile
88
+
89
+ # This option is passed to Sawmill::EntryProcessor::Format::new
90
+ attr_accessor :include_id
91
+ # This option is passed to Sawmill::EntryProcessor::Format::new
92
+ attr_accessor :fractional_second_digits
93
+ # This option is passed to Sawmill::EntryProcessor::Format::new
94
+ attr_accessor :level_width
95
+ # This option is passed to Sawmill::EntryProcessor::Format::new
96
+ attr_accessor :local_time
97
+ # This option is passed to Sawmill::EntryProcessor::Format::new
98
+ attr_accessor :iso_8601_time
99
+ # This option is passed to Sawmill::EntryProcessor::Format::new
100
+ attr_accessor :length_limit
101
+
102
+ # This option is passed to Sawmill::Logger::new
103
+ attr_accessor :level
104
+ # This option is passed to Sawmill::Logger::new
105
+ attr_accessor :attribute_level
106
+ # This option is passed to Sawmill::Logger::new
107
+ attr_accessor :progname
108
+ # This option is passed to Sawmill::Logger::new
109
+ attr_accessor :record_progname
110
+ # This option is passed to Sawmill::Logger::new
111
+ attr_accessor :record_id_generator
112
+
113
+ # This option is passed to Sawmill::LogRecordMiddleware::new
114
+ attr_accessor :request_id_key
115
+ # This option is passed to Sawmill::LogRecordMiddleware::new
116
+ attr_accessor :start_time_attribute
117
+ # This option is passed to Sawmill::LogRecordMiddleware::new
118
+ attr_accessor :end_time_attribute
119
+
120
+ end
121
+
122
+
123
+ config.sawmill = Configuration.new
124
+
125
+
126
+ initializer :initialize_sawmill, :before => :initialize_logger do |app_|
127
+ myconfig_ = app_.config.sawmill
128
+ formatter_ = Formatter.new(myconfig_.logfile || ::STDERR,
129
+ :include_id => myconfig_.include_id,
130
+ :fractional_second_digits => myconfig_.fractional_second_digits,
131
+ :level_width => myconfig_.level_width,
132
+ :local_time => myconfig_.local_time,
133
+ :iso_8601_time => myconfig_.iso_8601_time,
134
+ :length_limit => myconfig_.length_limit)
135
+ logger_ = Logger.new(:processor => formatter_,
136
+ :level => myconfig_.level,
137
+ :attribute_level => myconfig_.attribute_level,
138
+ :progname => myconfig_.progname,
139
+ :record_progname => myconfig_.record_progname,
140
+ :record_id_generator => myconfig_.record_id_generator)
141
+ app_.config.logger = logger_
142
+ app_.config.middleware.swap(::Rails::Rack::Logger,
143
+ ::Sawmill::LogRecordMiddleware, logger_,
144
+ :request_id_key => myconfig_.request_id_key,
145
+ :start_time_attribute => myconfig_.start_time_attribute,
146
+ :end_time_attribute => myconfig_.end_time_attribute)
147
+ end
148
+
149
+
150
+ end
151
+
152
+
153
+ end
@@ -76,15 +76,61 @@ module Sawmill
76
76
  # The logfile name prefix.
77
77
  # In the filename "rails.2009-10-11.log", the suffix is ".log".
78
78
  # If not specified, defaults to ".log".
79
+ # <tt>:uniquifier</tt>::
80
+ # If provided, log files are never reopened. (That is, they are
81
+ # opened with ::File::CREAT | ::File::EXCL.) The value of this
82
+ # parameter must be a proc that returns an actual file name to
83
+ # attempt to open. This proc is called repeatedly until it either
84
+ # returns a file path that does not yet exist, or signals failure
85
+ # by returning nil. See the session on Uniquifiers below.
79
86
  # <tt>:local_datestamps</tt>::
80
87
  # If true, use the local timezone to create datestamps.
81
88
  # The default is to use UTC.
89
+ #
90
+ # === Uniquifiers
91
+ #
92
+ # DateBasedLogFile provides a facility for ensuring that log files
93
+ # are written to by only one process, by generating unique file
94
+ # names for log files. This facility is useful, for example, if you
95
+ # are deploying via Phusion Passenger where you may have a variable
96
+ # number of rails processes, and you want each process to own its
97
+ # own logfile so entries in log records are not interleaved.
98
+ #
99
+ # To activate this feature, pass a proc to the <tt>:uniquifier</tt>
100
+ # option. When DateBasedLogFile wants to open a log file for
101
+ # writing, it first calls this proc. The proc should return a file
102
+ # path to try opening. DateBasedLogFile then tries to open the file
103
+ # with ::File::CREAT | ::File::EXCL, which will succeed only if the
104
+ # file has not already been created (e.g. by another process). If
105
+ # the file already exists, the proc will be called again, and
106
+ # repeatedly until it either returns a path that has not yet been
107
+ # created, or nil indicating that it has given up.
108
+ #
109
+ # The proc is passed a single hash that provides information about
110
+ # what path to generate, as well as space for the proc to store any
111
+ # state it wishes to persist through the process. These keys are
112
+ # given to the proc by DateBasedLogFile. Any other keys are
113
+ # available for use by the proc.
114
+ # <tt>:original_path</tt>::
115
+ # The original file path generated by DateBasedLogFile, which
116
+ # would have been used if there were no uniquifier.
117
+ # <tt>:last_path</tt>::
118
+ # The last path generated by the proc, or nil if this is the
119
+ # first time this proc is called for a particular logfile.
120
+ # <tt>:basedir</tt>::
121
+ # The basedir of the DateBasedLogFile.
122
+ # <tt>:path_prefix</tt>::
123
+ # The path_prefix of the DateBasedLogFile.
124
+ # <tt>:path_suffix</tt>::
125
+ # The path_suffix of the DateBasedLogFile.
82
126
 
83
127
  def initialize(options_)
84
128
  @turnover_frequency = options_[:turnover_frequency] || :none
85
- @prefix = ::File.expand_path(options_[:path_prefix] || options_[:prefix] || 'sawmill',
86
- options_[:basedir] || options_[:dirname] || ::Dir.getwd)
129
+ @basedir = options_[:basedir] || options_[:dirname] || ::Dir.getwd
130
+ @prefix = options_[:path_prefix] || options_[:prefix] || 'sawmill'
87
131
  @suffix = options_[:path_suffix] || options_[:suffix] || '.log'
132
+ @suffix = ".#{@suffix}" unless @suffix.length == 0 || @suffix[0,1] == '.'
133
+ @uniquifier = options_[:uniquifier]
88
134
  @local_datestamps = options_[:local_datestamps]
89
135
  @date_pattern =
90
136
  case @turnover_frequency
@@ -113,12 +159,24 @@ module Sawmill
113
159
  # Implements the rotation strategy contract.
114
160
 
115
161
  def open_handle(handle_)
116
- if @date_pattern
117
- path_ = "#{@prefix}.#{handle_}#{@suffix}"
162
+ path_ = ::File.expand_path(@date_pattern ? "#{@prefix}.#{handle_}#{@suffix}" : @prefix+@suffix, @basedir)
163
+ file_ = nil
164
+ if @uniquifier
165
+ hash_ = {:path_prefix => @prefix, :path_suffix => @suffix, :basedir => @basedir, :original_path => path_.dup, :last_path => nil}
166
+ until file_
167
+ path_ = @uniquifier.call(hash_)
168
+ unless path_
169
+ raise Errors::NoUniqueLogFileError, "Could not find a unique log file path for #{hash_.inspect}"
170
+ end
171
+ begin
172
+ file_ = ::File.open(path_, ::File::CREAT | ::File::EXCL | ::File::WRONLY)
173
+ rescue ::Errno::EEXIST
174
+ hash_[:last_path] = path_
175
+ end
176
+ end
118
177
  else
119
- path_ = @prefix+@suffix
178
+ file_ = ::File.open(path_, 'a')
120
179
  end
121
- file_ = ::File.open(path_, 'a')
122
180
  file_.sync = true
123
181
  file_
124
182
  end
@@ -137,6 +195,72 @@ module Sawmill
137
195
  end
138
196
 
139
197
 
198
+ class << self
199
+
200
+
201
+ # Returns a simple uniquifier that inserts an incrementing number
202
+ # before the path suffix. i.e. if the non-uniquified filename is
203
+ # "rails.2009-10-11.log", then these names are generated:
204
+ #
205
+ # rails.2009-10-11.0.log
206
+ # rails.2009-10-11.1.log
207
+ # rails.2009-10-11.2.log
208
+ # etc.
209
+ #
210
+ # The following options are available:
211
+ #
212
+ # <tt>:min_digits</tt>::
213
+ # If provided, indicates the minimum number of digits for the
214
+ # unique number. For example, if :digits is set to 2, these
215
+ # names are generated:
216
+ # rails.2009-10-11.00.log
217
+ # rails.2009-10-11.01.log
218
+ # rails.2009-10-11.02.log
219
+ # ...
220
+ # rails.2009-10-11.09.log
221
+ # rails.2009-10-11.10.log
222
+ # rails.2009-10-11.11.log
223
+ # ...
224
+ # rails.2009-10-11.99.log
225
+ # rails.2009-10-11.100.log
226
+ # rails.2009-10-11.101.log
227
+ # etc.
228
+ # The default is 1.
229
+ # <tt>:start_value</tt>::
230
+ # The first value for the unique number. Default is 0.
231
+
232
+ def simple_uniquifier(opts_={})
233
+ if (digits_ = opts_[:min_digits])
234
+ pattern_ = "%s.%0#{digits_.to_i}d%s"
235
+ else
236
+ pattern_ = "%s.%d%s"
237
+ end
238
+ ::Proc.new do |hash_|
239
+ if hash_[:last_path]
240
+ hash_[:value] += 1
241
+ else
242
+ suffix_ = hash_[:path_suffix]
243
+ orig_ = hash_[:original_path]
244
+ suffix_len_ = suffix_.length
245
+ if suffix_len_ > 0 && orig_[-suffix_len_, suffix_len_] == suffix_
246
+ pre_ = orig_[0, orig_.length - suffix_len_]
247
+ post_ = suffix_
248
+ else
249
+ pre_ = orig_
250
+ post_ = ''
251
+ end
252
+ hash_[:value] = opts_[:start_value].to_i
253
+ hash_[:pre] = pre_
254
+ hash_[:post] = post_
255
+ end
256
+ pattern_ % [hash_[:pre], hash_[:value], hash_[:post]]
257
+ end
258
+ end
259
+
260
+
261
+ end
262
+
263
+
140
264
  end
141
265
 
142
266
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 11
9
- version: 0.1.11
8
+ - 12
9
+ version: 0.1.12
10
10
  platform: ruby
11
11
  authors:
12
12
  - Daniel Azuma
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-19 00:00:00 -07:00
17
+ date: 2010-11-01 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -60,6 +60,7 @@ files:
60
60
  - lib/sawmill/logger.rb
61
61
  - lib/sawmill/multi_parser.rb
62
62
  - lib/sawmill/parser.rb
63
+ - lib/sawmill/railtie.rb
63
64
  - lib/sawmill/record.rb
64
65
  - lib/sawmill/record_processor/compile_report.rb
65
66
  - lib/sawmill/record_processor/conditionals.rb