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.
- 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
|