logging 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +12 -7
- data/Rakefile +4 -1
- data/data/logging.yaml +1 -1
- data/lib/logging.rb +4 -17
- data/lib/logging/appender.rb +23 -16
- data/lib/logging/appenders/console.rb +3 -5
- data/lib/logging/appenders/email.rb +127 -0
- data/lib/logging/appenders/file.rb +27 -15
- data/lib/logging/appenders/growl.rb +33 -56
- data/lib/logging/appenders/io.rb +16 -11
- data/lib/logging/appenders/rolling_file.rb +94 -31
- data/lib/logging/appenders/syslog.rb +32 -46
- data/lib/logging/layout.rb +5 -3
- data/lib/logging/layouts/pattern.rb +6 -6
- data/lib/logging/utils.rb +44 -0
- data/{tasks → rakelib}/doc.rake +2 -2
- data/{tasks → rakelib}/gem.rake +3 -3
- data/{tasks → rakelib}/manifest.rake +0 -0
- data/{tasks → rakelib}/rubyforge.rake +0 -0
- data/{tasks → rakelib}/setup.rb +1 -4
- data/{tasks → rakelib}/test.rake +0 -0
- data/{tasks → rakelib}/website.rake +0 -0
- data/test/appenders/test_email.rb +165 -0
- data/test/appenders/test_file.rb +13 -14
- data/test/appenders/test_growl.rb +115 -0
- data/test/appenders/test_io.rb +5 -3
- data/test/appenders/test_rolling_file.rb +3 -9
- data/test/appenders/test_syslog.rb +4 -8
- data/test/config/test_yaml_configurator.rb +1 -5
- data/test/setup.rb +14 -2
- data/test/test_appender.rb +14 -4
- data/test/test_logging.rb +2 -15
- data/test/test_utils.rb +49 -0
- metadata +86 -53
data/lib/logging/appenders/io.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
# $Id: io.rb
|
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
|
-
|
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(
|
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
|
-
#
|
65
|
-
#
|
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(
|
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
|
-
|
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
|
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::
|
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
|
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
|
-
|
69
|
-
@keep =
|
74
|
+
# grab our options
|
75
|
+
@keep = opts.getopt(:keep, :as => Integer)
|
76
|
+
@size = opts.getopt(:size, :as => Integer)
|
70
77
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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.
|
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
|
-
|
137
|
-
|
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(
|
153
|
+
# write( event, do_layout = true )
|
145
154
|
#
|
146
|
-
# Write the given
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
189
|
+
@io.close rescue nil
|
164
190
|
roll_files
|
165
|
-
|
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
|
176
|
-
@file_size =
|
177
|
-
|
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
|
-
|
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
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
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
|
data/lib/logging/layout.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: layout.rb
|
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
|
-
|
36
|
-
|
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
|
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
|
-
@
|
231
|
-
@
|
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
|