logging 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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