logging 0.5.3 → 0.6.0

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.
@@ -1,9 +1,8 @@
1
- # $Id: io.rb 37 2007-10-26 19:12:44Z tim_pease $
1
+ # $Id: io.rb 72 2007-12-26 21:59:58Z tim_pease $
2
2
 
3
3
  require 'logging/appender'
4
4
 
5
- module Logging
6
- module Appenders
5
+ module Logging::Appenders
7
6
 
8
7
  # This class provides an Appender that can write to any IO stream
9
8
  # configured for writing.
@@ -40,7 +39,9 @@ module Appenders
40
39
  super(*args)
41
40
  io, @io = @io, nil
42
41
  io.close unless [STDIN, STDERR, STDOUT].include?(io)
43
- self
42
+ rescue IOError => err
43
+ ensure
44
+ return self
44
45
  end
45
46
 
46
47
  # call-seq:
@@ -59,22 +60,26 @@ module Appenders
59
60
  private
60
61
 
61
62
  # call-seq:
62
- # write( str )
63
+ # write( event, do_layout = true )
64
+ #
65
+ # Writes the given _event_ to the IO stream. If an +IOError+ is detected,
66
+ # than this appender will be turned off and the error reported.
63
67
  #
64
- # Writes the given string to the IO stream. If an +IOError+ is detected,
65
- # than this appender will be closed and the error reported.
68
+ # If the _do_layout_ flag is set to +true+, then the event will be
69
+ # formatted using the configured layout object. If set to false, then
70
+ # the event will be stringiied and appended to the IO stream.
66
71
  #
67
- def write( str )
72
+ def write( event, do_layout = true )
68
73
  begin
74
+ str = do_layout ? @layout.format(event) : event.to_s
69
75
  @io.print str
70
76
  rescue IOError
71
- close false
77
+ self.level = :off
72
78
  raise
73
79
  end
74
80
  end
75
81
 
76
82
  end # class IO
77
- end # module Appenders
78
- end # module Logging
83
+ end # module Logging::Appenders
79
84
 
80
85
  # EOF
@@ -1,6 +1,7 @@
1
- # $Id: rolling_file.rb 37 2007-10-26 19:12:44Z tim_pease $
1
+ # $Id: rolling_file.rb 67 2007-12-26 16:27:06Z tim_pease $
2
2
 
3
3
  require 'logging/appenders/file'
4
+ require 'lockfile'
4
5
 
5
6
  module Logging::Appenders
6
7
 
@@ -28,7 +29,7 @@ module Logging::Appenders
28
29
  # The actual process of rolling all the log file names can be expensive if
29
30
  # there are many, many older log files to process.
30
31
  #
31
- class RollingFile < ::Logging::Appenders::File
32
+ class RollingFile < ::Logging::Appenders::IO
32
33
 
33
34
  # call-seq:
34
35
  # RollingFile.new( name, opts )
@@ -52,11 +53,16 @@ module Logging::Appenders
52
53
  # rolled. The age can also be given as 'daily', 'weekly',
53
54
  # or 'monthly'.
54
55
  # [:keep] The number of rolled log files to keep.
56
+ # [:safe] When set to true, extra checks are made to ensure that
57
+ # only once process can roll the log files; this option
58
+ # should only be used when multiple processes will be
59
+ # logging to the same log file (does not work on Windows)
55
60
  #
56
61
  def initialize( name, opts = {} )
57
62
  # raise an error if a filename was not given
58
- @fn = opts[:filename] || opts['filename']
63
+ @fn = opts.getopt(:filename, name)
59
64
  raise ArgumentError, 'no filename was given' if @fn.nil?
65
+ ::Logging::Appenders::File.assert_valid_logfile(@fn)
60
66
 
61
67
  # grab the information we need to properly roll files
62
68
  ext = ::File.extname(@fn)
@@ -65,21 +71,21 @@ module Logging::Appenders
65
71
  @glob = "#{bn}.*#{ext}"
66
72
  @logname_fmt = "#{bn}.%d#{ext}"
67
73
 
68
- @keep = opts.delete(:keep) || opts.delete('keep')
69
- @keep = Integer(@keep) unless @keep.nil?
74
+ # grab our options
75
+ @keep = opts.getopt(:keep, :as => Integer)
76
+ @size = opts.getopt(:size, :as => Integer)
70
77
 
71
- # if the truncate flag was set to true, then roll
72
- roll_now = opts.delete(:truncate) || opts.delete('truncate')
73
- roll_files if roll_now
74
-
75
- # grab out our options
76
- @size = opts.delete(:size) || opts.delete('size')
77
- @size = Integer(@size) unless @size.nil?
78
+ @lockfile = if opts.getopt(:safe, false) and !(%r/win32/ =~ RUBY_PLATFORM)
79
+ Lockfile.new(
80
+ @fn + '.lck',
81
+ :retries => 1,
82
+ :timeout => 2
83
+ )
84
+ end
78
85
 
79
86
  code = 'def sufficiently_aged?() false end'
80
87
 
81
- @age = opts.delete(:age) || opts.delete('age')
82
- case @age
88
+ case @age = opts.getopt(:age)
83
89
  when 'daily'
84
90
  @start_time = Time.now
85
91
  code = <<-CODE
@@ -133,25 +139,45 @@ module Logging::Appenders
133
139
  meta = class << self; self end
134
140
  meta.class_eval code
135
141
 
136
- @file_size = (::File.exist?(@fn) ? ::File.size(@fn) : 0)
137
- super(name, opts)
142
+ # if the truncate flag was set to true, then roll
143
+ roll_now = opts.getopt(:truncate, false)
144
+ roll_files if roll_now
145
+
146
+ super(name, open_logfile, opts)
138
147
  end
139
148
 
140
149
 
141
150
  private
142
151
 
143
152
  # call-seq:
144
- # write( str )
153
+ # write( event, do_layout = true )
145
154
  #
146
- # Write the given string to the log file. The log file will be rolled
155
+ # Write the given _event_ to the log file. The log file will be rolled
147
156
  # if the maximum file size is exceeded or if the file is older than the
148
157
  # maximum age.
149
158
  #
150
- def write( str )
151
- super
152
- @file_size += str.size # keep track of the size internally since
153
- roll if roll_required? # the file IO stream is probably not being
154
- end # flushed to disk immediately
159
+ # If the _do_layout_ flag is set to +true+, then the event will be
160
+ # formatted using the configured layout object. If set to false, then
161
+ # the event will be stringiied and appended to the current log file.
162
+ #
163
+ def write( event, do_layout = true )
164
+ check_logfile
165
+
166
+ str = do_layout ? @layout.format(event) : event.to_s
167
+ super(str, false)
168
+
169
+ if roll_required?(str)
170
+ return roll unless @lockfile
171
+
172
+ begin
173
+ @lockfile.lock
174
+ check_logfile
175
+ roll if roll_required?
176
+ ensure
177
+ @lockfile.unlock
178
+ end
179
+ end
180
+ end
155
181
 
156
182
  # call-seq:
157
183
  # roll
@@ -160,25 +186,28 @@ module Logging::Appenders
160
186
  # new log file.
161
187
  #
162
188
  def roll
163
- begin; @io.close; rescue; end
189
+ @io.close rescue nil
164
190
  roll_files
165
- @io = ::File.new(@fn, 'a')
191
+ open_logfile
166
192
  end
167
193
 
168
194
  # call-seq:
169
- # roll_required?
195
+ # roll_required?( str ) => true or false
170
196
  #
171
197
  # Returns +true+ if the log file needs to be rolled.
172
198
  #
173
- def roll_required?
199
+ def roll_required?( str = nil )
174
200
  # check if max size has been exceeded
175
- if @size and @file_size > @size
176
- @file_size = 0
177
- return true
201
+ s = if @size
202
+ @file_size = @stat.size if @stat.size > @file_size
203
+ @file_size += str.size if str
204
+ @file_size > @size
178
205
  end
179
206
 
180
207
  # check if max age has been exceeded
181
- return sufficiently_aged?
208
+ a = sufficiently_aged?
209
+
210
+ return (s || a)
182
211
  end
183
212
 
184
213
  # call-seq:
@@ -227,6 +256,40 @@ module Logging::Appenders
227
256
  ::File.rename(@fn, sprintf(@logname_fmt, 1))
228
257
  end
229
258
 
259
+ # call-seq:
260
+ # open_logfile => io
261
+ #
262
+ # Opens the logfile and stores the current file szie and inode.
263
+ #
264
+ def open_logfile
265
+ @io = ::File.new(@fn, 'a')
266
+ @io.sync = true
267
+
268
+ @stat = ::File.stat(@fn)
269
+ @file_size = @stat.size
270
+ @inode = @stat.ino
271
+
272
+ return @io
273
+ end
274
+
275
+ #
276
+ #
277
+ def check_logfile
278
+ retry_cnt ||= 0
279
+
280
+ @stat = ::File.stat(@fn)
281
+ return unless @lockfile
282
+ return if @inode == @stat.ino
283
+
284
+ @io.close rescue nil
285
+ open_logfile
286
+ rescue SystemCallError
287
+ raise if retry_cnt > 3
288
+ retry_cnt += 1
289
+ sleep 0.08
290
+ retry
291
+ end
292
+
230
293
  end # class RollingFile
231
294
  end # module Logging::Appenders
232
295
 
@@ -1,4 +1,4 @@
1
- # $Id: syslog.rb 52 2007-11-27 23:53:23Z tim_pease $
1
+ # $Id: syslog.rb 72 2007-12-26 21:59:58Z tim_pease $
2
2
 
3
3
  begin
4
4
  require 'logging/appender'
@@ -13,8 +13,7 @@ end
13
13
  #
14
14
  if HAVE_SYSLOG
15
15
 
16
- module Logging
17
- module Appenders
16
+ module Logging::Appenders
18
17
 
19
18
  # This class provides an Appender that can write to the UNIX syslog
20
19
  # daemon.
@@ -96,20 +95,19 @@ module Appenders
96
95
  # through LOG_LOCAL7.
97
96
  #
98
97
  def initialize( name, opts = {} )
99
- super
100
-
101
- ident = opts[:ident] || opts['ident'] || name
102
- logopt = opts[:logopt] || opts['logopt'] || (LOG_PID | LOG_CONS)
103
- facility = opts[:facility] || opts['facility'] || LOG_USER
104
- @syslog = ::Syslog.open(ident, Integer(logopt), Integer(facility))
98
+ ident = opts.getopt(:ident, name)
99
+ logopt = opts.getopt(:logopt, (LOG_PID | LOG_CONS), :as => Integer)
100
+ facility = opts.getopt(:facility, LOG_USER, :as => Integer)
101
+ @syslog = ::Syslog.open(ident, logopt, facility)
105
102
 
106
103
  # provides a mapping from the default Logging levels
107
104
  # to the syslog levels
108
105
  @map = [LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT]
109
106
 
110
- if opts.has_key?('map') or opts.has_key?(:map)
111
- self.map = opts[:map] || opts['map']
112
- end
107
+ map = opts.getopt(:map)
108
+ self.map = map unless map.nil?
109
+
110
+ super
113
111
  end
114
112
 
115
113
  # call-seq:
@@ -140,8 +138,10 @@ module Appenders
140
138
  #
141
139
  # Closes the connetion to the syslog facility.
142
140
  #
143
- def close
141
+ def close( footer = true )
142
+ super
144
143
  @syslog.close
144
+ self
145
145
  end
146
146
 
147
147
  # call-seq:
@@ -154,47 +154,35 @@ module Appenders
154
154
  !@syslog.opened?
155
155
  end
156
156
 
157
- # call-seq:
158
- # append( event )
159
- #
160
- # Write the given _event_ to the syslog facility. The log event will be
161
- # processed through the Layout assciated with this appender. The message
162
- # will be logged at the level specified by the event.
163
- #
164
- def append( event )
165
- if closed?
166
- raise RuntimeError,
167
- "appender '<#{self.class.name}: #{@name}>' is closed"
168
- end
169
157
 
170
- sync do
171
- msg = @layout.format(event)
172
- pri = @map[event.level]
173
- @syslog.log(pri, '%s', msg)
174
- end unless @level > event.level
175
- self
176
- end
158
+ private
177
159
 
178
160
  # call-seq:
179
- # syslog << string
161
+ # write( event, do_layout = true )
162
+ #
163
+ # Write the given _event_ to the syslog facility. The log event will be
164
+ # processed through the Layout assciated with this appender if the
165
+ # _do_layout_ flag is set to +true+. The message will be logged at the
166
+ # level specified by the event.
180
167
  #
181
- # Write the given _string_ to the syslog facility "as is" -- no
168
+ # If the _do_layout_ flag is set to +false+, the _event_ will be
169
+ # converted to a string and wirtten to the syslog facility "as is" -- no
182
170
  # layout formatting will be performed. The string will be logged at the
183
171
  # LOG_DEBUG level of the syslog facility.
184
172
  #
185
- def <<( str )
186
- if closed?
187
- raise RuntimeError,
188
- "appender '<#{self.class.name}: #{@name}>' is closed"
189
- end
173
+ def write( event, do_layout = true )
174
+ pri = LOG_DEBUG
175
+ msg = if do_layout
176
+ pri = @map[event.level]
177
+ @layout.format(event)
178
+ else
179
+ event.to_s
180
+ end
190
181
 
191
- sync {@syslog.log(LOG_DEBUG, '%s', str)}
182
+ @syslog.log(pri, '%s', msg)
192
183
  self
193
184
  end
194
185
 
195
-
196
- private
197
-
198
186
  # call-seq:
199
187
  # syslog_level_num( level ) => integer
200
188
  #
@@ -214,9 +202,7 @@ module Appenders
214
202
 
215
203
  end # class Syslog
216
204
 
217
- end # module Appenders
218
- end # module Logging
219
-
205
+ end # module Logging::Appenders
220
206
  end # HAVE_SYSLOG
221
207
 
222
208
  # EOF
@@ -1,4 +1,4 @@
1
- # $Id: layout.rb 52 2007-11-27 23:53:23Z tim_pease $
1
+ # $Id: layout.rb 62 2007-12-22 20:37:05Z tim_pease $
2
2
 
3
3
  require 'yaml'
4
4
  require 'logging'
@@ -32,8 +32,10 @@ module Logging
32
32
  # then <tt>:string</tt> is used.
33
33
  #
34
34
  def initialize( opts = {} )
35
- f = opts[:format_as] || opts['format_as']
36
- f ||= ::Logging::OBJ_FORMAT if ::Logging.const_defined? 'OBJ_FORMAT'
35
+ default = ::Logging.const_defined?('OBJ_FORMAT') ?
36
+ ::Logging::OBJ_FORMAT : nil
37
+
38
+ f = opts.getopt(:format_as, default)
37
39
  f = f.intern if f.instance_of? String
38
40
 
39
41
  @obj_format = case f
@@ -1,4 +1,4 @@
1
- # $Id: pattern.rb 52 2007-11-27 23:53:23Z tim_pease $
1
+ # $Id: pattern.rb 62 2007-12-22 20:37:05Z tim_pease $
2
2
 
3
3
  require 'logging'
4
4
  require 'logging/layout'
@@ -227,13 +227,13 @@ module Layouts
227
227
  super
228
228
  @created_at = Time.now
229
229
 
230
- @pattern = opts[:pattern] || opts['pattern']
231
- @date_pattern = opts[:date_pattern] || opts['date_pattern']
232
- @date_method = opts[:date_method] || opts['date_method']
233
-
234
- @pattern ||= "[%d] %-#{::Logging::MAX_LEVEL_LENGTH}l -- %c : %m\n"
230
+ @date_pattern = opts.getopt(:date_pattern)
231
+ @date_method = opts.getopt(:date_method)
235
232
  @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil?
236
233
 
234
+ @pattern = opts.getopt(:pattern,
235
+ "[%d] %-#{::Logging::MAX_LEVEL_LENGTH}l -- %c : %m\n")
236
+
237
237
  Pattern.create_date_format_methods(self)
238
238
  Pattern.create_format_method(self)
239
239
  end
@@ -0,0 +1,44 @@
1
+ # $Id: utils.rb 65 2007-12-23 04:48:55Z tim_pease $
2
+
3
+ class Hash
4
+
5
+ # call-seq:
6
+ # getopt( key, default = nil, :as => class )
7
+ #
8
+ # Returns the value associated with the _key_. If the has does not contain
9
+ # the _key_, then the _default_ value is returned.
10
+ #
11
+ # Optionally, the value can be converted into to an instance of the given
12
+ # _class_. The supported classes are:
13
+ #
14
+ # Integer
15
+ # Float
16
+ # Array
17
+ # String
18
+ # Symbol
19
+ #
20
+ # If the value is +nil+, then no converstion will be performed.
21
+ #
22
+ def getopt( *args )
23
+ opts = Hash === args.last ? args.pop : {}
24
+ key, default = args
25
+
26
+ val = if has_key?(key); self[key]
27
+ elsif has_key?(key.to_s); self[key.to_s]
28
+ elsif has_key?(key.to_s.intern); self[key.to_s.intern]
29
+ else default end
30
+
31
+ return if val.nil?
32
+ return val unless opts.has_key?(:as)
33
+
34
+ case opts[:as].name.intern
35
+ when :Integer; Integer(val)
36
+ when :Float; Float(val)
37
+ when :Array; Array(val)
38
+ when :String; String(val)
39
+ when :Symbol; String(val).intern
40
+ else val end
41
+ end
42
+ end
43
+
44
+ # EOF