sgeorgi-logging 1.4.2
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 +262 -0
- data/README.rdoc +115 -0
- data/Rakefile +32 -0
- data/data/bad_logging_1.rb +13 -0
- data/data/bad_logging_2.rb +21 -0
- data/data/logging.rb +42 -0
- data/data/logging.yaml +63 -0
- data/data/simple_logging.rb +13 -0
- data/examples/appenders.rb +47 -0
- data/examples/classes.rb +41 -0
- data/examples/consolidation.rb +83 -0
- data/examples/fork.rb +37 -0
- data/examples/formatting.rb +51 -0
- data/examples/hierarchies.rb +73 -0
- data/examples/layouts.rb +48 -0
- data/examples/loggers.rb +29 -0
- data/examples/names.rb +43 -0
- data/examples/simple.rb +17 -0
- data/lib/logging.rb +528 -0
- data/lib/logging/appender.rb +260 -0
- data/lib/logging/appenders.rb +137 -0
- data/lib/logging/appenders/buffering.rb +178 -0
- data/lib/logging/appenders/console.rb +60 -0
- data/lib/logging/appenders/email.rb +75 -0
- data/lib/logging/appenders/file.rb +75 -0
- data/lib/logging/appenders/growl.rb +197 -0
- data/lib/logging/appenders/io.rb +69 -0
- data/lib/logging/appenders/rolling_file.rb +327 -0
- data/lib/logging/appenders/string_io.rb +68 -0
- data/lib/logging/appenders/syslog.rb +210 -0
- data/lib/logging/config/configurator.rb +188 -0
- data/lib/logging/config/yaml_configurator.rb +191 -0
- data/lib/logging/layout.rb +117 -0
- data/lib/logging/layouts.rb +47 -0
- data/lib/logging/layouts/basic.rb +32 -0
- data/lib/logging/layouts/parseable.rb +211 -0
- data/lib/logging/layouts/pattern.rb +311 -0
- data/lib/logging/log_event.rb +45 -0
- data/lib/logging/logger.rb +504 -0
- data/lib/logging/repository.rb +232 -0
- data/lib/logging/root_logger.rb +61 -0
- data/lib/logging/stats.rb +278 -0
- data/lib/logging/utils.rb +201 -0
- data/lib/spec/logging_helper.rb +34 -0
- data/test/appenders/test_buffered_io.rb +176 -0
- data/test/appenders/test_console.rb +66 -0
- data/test/appenders/test_email.rb +170 -0
- data/test/appenders/test_file.rb +95 -0
- data/test/appenders/test_growl.rb +127 -0
- data/test/appenders/test_io.rb +129 -0
- data/test/appenders/test_rolling_file.rb +209 -0
- data/test/appenders/test_syslog.rb +194 -0
- data/test/benchmark.rb +86 -0
- data/test/config/test_configurator.rb +70 -0
- data/test/config/test_yaml_configurator.rb +40 -0
- data/test/layouts/test_basic.rb +42 -0
- data/test/layouts/test_json.rb +112 -0
- data/test/layouts/test_pattern.rb +198 -0
- data/test/layouts/test_yaml.rb +121 -0
- data/test/setup.rb +43 -0
- data/test/test_appender.rb +152 -0
- data/test/test_consolidate.rb +46 -0
- data/test/test_layout.rb +110 -0
- data/test/test_log_event.rb +80 -0
- data/test/test_logger.rb +699 -0
- data/test/test_logging.rb +267 -0
- data/test/test_repository.rb +158 -0
- data/test/test_root_logger.rb +81 -0
- data/test/test_stats.rb +274 -0
- data/test/test_utils.rb +116 -0
- data/version.txt +1 -0
- metadata +227 -0
@@ -0,0 +1,201 @@
|
|
1
|
+
|
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 = args.last.instance_of?(Hash) ? 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
|
+
# --------------------------------------------------------------------------
|
45
|
+
class String
|
46
|
+
|
47
|
+
# call-seq:
|
48
|
+
# reduce( width, ellipses = '...' ) #=> string
|
49
|
+
#
|
50
|
+
# Reduce the size of the current string to the given _width_ by removing
|
51
|
+
# characters from the middle of the string and replacing them with
|
52
|
+
# _ellipses_. If the _width_ is greater than the length of the string, the
|
53
|
+
# string is returned unchanged. If the _width_ is less than the length of
|
54
|
+
# the _ellipses_, then the _ellipses_ are returned.
|
55
|
+
#
|
56
|
+
def reduce( width, ellipses = '...')
|
57
|
+
raise ArgumentError, "width cannot be negative: #{width}" if width < 0
|
58
|
+
|
59
|
+
return self if length <= width
|
60
|
+
|
61
|
+
remove = length - width + ellipses.length
|
62
|
+
return ellipses.dup if remove >= length
|
63
|
+
|
64
|
+
left_end = (length + 1 - remove) / 2
|
65
|
+
right_start = left_end + remove
|
66
|
+
|
67
|
+
left = self[0,left_end]
|
68
|
+
right = self[right_start,length-right_start]
|
69
|
+
|
70
|
+
left << ellipses << right
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# --------------------------------------------------------------------------
|
75
|
+
class Module
|
76
|
+
|
77
|
+
# call-seq:
|
78
|
+
# logger_name #=> string
|
79
|
+
#
|
80
|
+
# Returns a predictable logger name for the current module or class. If
|
81
|
+
# used within an anonymous class, the first non-anonymous class name will
|
82
|
+
# be used as the logger name. If used within a meta-class, the name of the
|
83
|
+
# actual class will be used as the logger name. If used within an
|
84
|
+
# anonymous module, the string 'anonymous' will be returned.
|
85
|
+
#
|
86
|
+
def logger_name
|
87
|
+
return name unless name.nil? or name.empty?
|
88
|
+
|
89
|
+
# check if this is a metaclass (or eigenclass)
|
90
|
+
if ancestors.include? Class
|
91
|
+
inspect =~ %r/#<Class:([^#>]+)>/
|
92
|
+
return $1
|
93
|
+
end
|
94
|
+
|
95
|
+
# see if we have a superclass
|
96
|
+
if respond_to? :superclass
|
97
|
+
return superclass.logger_name
|
98
|
+
end
|
99
|
+
|
100
|
+
# we are an anonymous module
|
101
|
+
::Logging.log_internal(-2) {
|
102
|
+
'cannot return a predictable, unique name for anonymous modules'
|
103
|
+
}
|
104
|
+
return 'anonymous'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# --------------------------------------------------------------------------
|
109
|
+
module Kernel
|
110
|
+
|
111
|
+
# call-seq:
|
112
|
+
# require?( string )
|
113
|
+
#
|
114
|
+
# Attempt to the load the library named _string_ using the standard
|
115
|
+
# Kernel#require method. Returns +true+ if the library was successfully
|
116
|
+
# loaded. Returns +false+ if the library could not be loaded. This method
|
117
|
+
# will never raise an exception.
|
118
|
+
#
|
119
|
+
def require?( string )
|
120
|
+
require string
|
121
|
+
return true
|
122
|
+
rescue LoadError
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
end # module Kernel
|
126
|
+
|
127
|
+
# --------------------------------------------------------------------------
|
128
|
+
class File
|
129
|
+
|
130
|
+
# Returns <tt>true</tt> if another process holds an exclusive lock on the
|
131
|
+
# file. Returns <tt>false</tt> if this is not the case.
|
132
|
+
#
|
133
|
+
# If a <tt>block</tt> of code is passed to this method, it will be run iff
|
134
|
+
# this process can obtain an exclusive lock on the file. The block will be
|
135
|
+
# run while this lock is held, and the exclusive lock will be released when
|
136
|
+
# the method returns.
|
137
|
+
#
|
138
|
+
# The exclusive lock is requested in a non-blocking mode. This method will
|
139
|
+
# return immediately (and the block will not be executed) if an exclusive
|
140
|
+
# lock cannot be obtained.
|
141
|
+
#
|
142
|
+
def flock?( &block )
|
143
|
+
status = flock(LOCK_EX|LOCK_NB)
|
144
|
+
case status
|
145
|
+
when false; true
|
146
|
+
when 0; block ? block.call : false
|
147
|
+
else
|
148
|
+
raise SystemCallError, "flock failed with status: #{status}"
|
149
|
+
end
|
150
|
+
ensure
|
151
|
+
flock LOCK_UN
|
152
|
+
end
|
153
|
+
|
154
|
+
# Execute the <tt>block</tt> in the context of a shared lock on this file. A
|
155
|
+
# shared lock will be obtained on the file, the block executed, and the lock
|
156
|
+
# released.
|
157
|
+
#
|
158
|
+
def flock_sh( &block )
|
159
|
+
flock LOCK_SH
|
160
|
+
block.call
|
161
|
+
ensure
|
162
|
+
flock LOCK_UN
|
163
|
+
end
|
164
|
+
|
165
|
+
# :stopdoc:
|
166
|
+
if %r/mswin|mingw/ =~ RUBY_PLATFORM
|
167
|
+
undef :flock?, :flock_sh
|
168
|
+
def flock?() yield; end
|
169
|
+
def flock_sh() yield; end
|
170
|
+
end
|
171
|
+
# :startdoc:
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
# --------------------------------------------------------------------------
|
176
|
+
class ReentrantMutex < Mutex
|
177
|
+
|
178
|
+
def initialize
|
179
|
+
super
|
180
|
+
@locker = nil
|
181
|
+
end
|
182
|
+
|
183
|
+
alias :original_synchronize :synchronize
|
184
|
+
|
185
|
+
def synchronize
|
186
|
+
if @locker == Thread.current
|
187
|
+
yield
|
188
|
+
else
|
189
|
+
original_synchronize {
|
190
|
+
begin
|
191
|
+
@locker = Thread.current
|
192
|
+
yield
|
193
|
+
ensure
|
194
|
+
@locker = nil
|
195
|
+
end
|
196
|
+
}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end # class ReentrantMutex
|
200
|
+
|
201
|
+
# EOF
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Spec
|
3
|
+
module LoggingHelper
|
4
|
+
|
5
|
+
# Capture log messages from the Logging framework and make them
|
6
|
+
# available via a @log_output instance variable. The @log_output
|
7
|
+
# supports a readline method to access the log messags.
|
8
|
+
#
|
9
|
+
def capture_log_messages( opts = {} )
|
10
|
+
from = opts.getopt(:from, 'root')
|
11
|
+
to = opts.getopt(:to, '__rspec__')
|
12
|
+
exclusive = opts.getopt(:exclusive, true)
|
13
|
+
|
14
|
+
appender = Logging::Appenders[to] || Logging::Appenders::StringIo.new(to)
|
15
|
+
logger = Logging::Logger[from]
|
16
|
+
if exclusive
|
17
|
+
logger.appenders = appender
|
18
|
+
else
|
19
|
+
logger.add_appenders(appender)
|
20
|
+
end
|
21
|
+
|
22
|
+
before(:all) do
|
23
|
+
@log_output = Logging::Appenders[to]
|
24
|
+
end
|
25
|
+
|
26
|
+
before(:each) do
|
27
|
+
@log_output.reset
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end # module LoggingHelper
|
32
|
+
end # module Spec
|
33
|
+
|
34
|
+
# EOF
|
@@ -0,0 +1,176 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[.. setup])
|
3
|
+
|
4
|
+
module TestLogging
|
5
|
+
module TestAppenders
|
6
|
+
|
7
|
+
class TestBufferedIO < Test::Unit::TestCase
|
8
|
+
include LoggingTestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
@appender = Logging.appenders.string_io(
|
13
|
+
'test_appender', :auto_flushing => 3, :immediate_at => :error
|
14
|
+
)
|
15
|
+
@appender.clear
|
16
|
+
@sio = @appender.sio
|
17
|
+
@levels = Logging::LEVELS
|
18
|
+
begin readline rescue EOFError end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_append
|
22
|
+
event = Logging::LogEvent.new('TestLogger', @levels['warn'],
|
23
|
+
[1, 2, 3, 4], false)
|
24
|
+
@appender.append event
|
25
|
+
assert_nil(readline)
|
26
|
+
|
27
|
+
@appender.append event
|
28
|
+
assert_nil(readline)
|
29
|
+
|
30
|
+
event.level = @levels['debug']
|
31
|
+
event.data = 'the big log message'
|
32
|
+
@appender.append event
|
33
|
+
|
34
|
+
assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
|
35
|
+
assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
|
36
|
+
assert_equal "DEBUG TestLogger : the big log message\n", readline
|
37
|
+
assert_nil(readline)
|
38
|
+
|
39
|
+
@appender.close
|
40
|
+
assert_raise(RuntimeError) {@appender.append event}
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_append_error
|
44
|
+
# setup an internal logger to capture error messages from the IO
|
45
|
+
# appender
|
46
|
+
log = Logging.appenders.string_io('__internal_io')
|
47
|
+
Logging.logger[Logging].add_appenders(log)
|
48
|
+
Logging.logger[Logging].level = 'all'
|
49
|
+
|
50
|
+
|
51
|
+
# close the string IO object so we get an error
|
52
|
+
@sio.close
|
53
|
+
event = Logging::LogEvent.new('TestLogger', @levels['warn'],
|
54
|
+
[1, 2, 3, 4], false)
|
55
|
+
@appender.append event
|
56
|
+
assert_nil(log.readline)
|
57
|
+
|
58
|
+
@appender.append event
|
59
|
+
assert_nil(log.readline)
|
60
|
+
|
61
|
+
@appender.append event
|
62
|
+
assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
|
63
|
+
assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
|
64
|
+
|
65
|
+
assert_equal false, @appender.closed?
|
66
|
+
assert_equal 5, @appender.level
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_auto_flushing
|
70
|
+
assert_raise(ArgumentError) {
|
71
|
+
@appender.auto_flushing = Object.new
|
72
|
+
}
|
73
|
+
|
74
|
+
assert_raise(ArgumentError) {
|
75
|
+
@appender.auto_flushing = -1
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_close
|
80
|
+
assert_equal false, @sio.closed?
|
81
|
+
assert_equal false, @appender.closed?
|
82
|
+
|
83
|
+
@appender.close
|
84
|
+
assert_equal true, @sio.closed?
|
85
|
+
assert_equal true, @appender.closed?
|
86
|
+
|
87
|
+
[STDIN, STDERR, STDOUT].each do |io|
|
88
|
+
@appender = Logging.appenders.io('test', io)
|
89
|
+
@appender.close
|
90
|
+
assert_equal false, io.closed?
|
91
|
+
assert_equal true, @appender.closed?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_concat
|
96
|
+
@appender << "this is a test message\n"
|
97
|
+
assert_nil(readline)
|
98
|
+
|
99
|
+
@appender << "this is another message\n"
|
100
|
+
assert_nil(readline)
|
101
|
+
|
102
|
+
@appender << "some other line\n"
|
103
|
+
|
104
|
+
assert_equal "this is a test message\n", readline
|
105
|
+
assert_equal "this is another message\n", readline
|
106
|
+
assert_equal "some other line\n", readline
|
107
|
+
assert_nil(readline)
|
108
|
+
|
109
|
+
@appender.close
|
110
|
+
assert_raise(RuntimeError) {@appender << 'message'}
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_concat_error
|
114
|
+
# setup an internal logger to capture error messages from the IO
|
115
|
+
# appender
|
116
|
+
log = Logging.appenders.string_io('__internal_io')
|
117
|
+
Logging.logger[Logging].add_appenders(log)
|
118
|
+
Logging.logger[Logging].level = 'all'
|
119
|
+
|
120
|
+
# close the string IO object so we get an error
|
121
|
+
@sio.close
|
122
|
+
@appender << 'oopsy'
|
123
|
+
assert_nil(log.readline)
|
124
|
+
|
125
|
+
@appender << 'whoopsy'
|
126
|
+
assert_nil(log.readline)
|
127
|
+
|
128
|
+
@appender << 'pooh'
|
129
|
+
assert_equal "INFO Logging : appender \"test_appender\" has been disabled", log.readline.strip
|
130
|
+
assert_equal "ERROR Logging : <IOError> not opened for writing", log.readline.strip
|
131
|
+
|
132
|
+
# and the appender does not close itself
|
133
|
+
assert_equal false, @appender.closed?
|
134
|
+
assert_equal 5, @appender.level
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_flush
|
138
|
+
ary = []
|
139
|
+
@sio.instance_variable_set :@ary, ary
|
140
|
+
def @sio.flush() @ary << :flush end
|
141
|
+
|
142
|
+
@appender << "this is a test message\n"
|
143
|
+
assert_nil(readline)
|
144
|
+
|
145
|
+
@appender.flush
|
146
|
+
assert_equal :flush, ary.pop
|
147
|
+
assert_equal "this is a test message\n", readline
|
148
|
+
assert_nil(readline)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_immediate_at
|
152
|
+
event = Logging::LogEvent.new('TestLogger', @levels['warn'],
|
153
|
+
[1, 2, 3, 4], false)
|
154
|
+
@appender.append event
|
155
|
+
assert_nil(readline)
|
156
|
+
|
157
|
+
event.level = @levels['error']
|
158
|
+
event.data = 'an error message'
|
159
|
+
@appender.append event
|
160
|
+
|
161
|
+
assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
|
162
|
+
assert_equal "ERROR TestLogger : an error message\n", readline
|
163
|
+
assert_nil(readline)
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
def readline
|
168
|
+
@appender.readline
|
169
|
+
end
|
170
|
+
|
171
|
+
end # class TestBufferedIO
|
172
|
+
|
173
|
+
end # module TestAppenders
|
174
|
+
end # module TestLogging
|
175
|
+
|
176
|
+
# EOF
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[.. setup])
|
3
|
+
|
4
|
+
module TestLogging
|
5
|
+
module TestAppenders
|
6
|
+
|
7
|
+
class TestStdout < Test::Unit::TestCase
|
8
|
+
include LoggingTestCase
|
9
|
+
|
10
|
+
def test_initialize
|
11
|
+
Logging::Repository.instance
|
12
|
+
|
13
|
+
appender = Logging.appenders.stdout
|
14
|
+
assert_equal 'stdout', appender.name
|
15
|
+
assert_same STDOUT, appender.instance_variable_get(:@io)
|
16
|
+
|
17
|
+
appender.close
|
18
|
+
assert_equal true, appender.closed?
|
19
|
+
assert_equal false, STDOUT.closed?
|
20
|
+
|
21
|
+
appender = Logging.appenders.stdout('foo')
|
22
|
+
assert_equal 'foo', appender.name
|
23
|
+
|
24
|
+
appender = Logging.appenders.stdout(:level => :warn)
|
25
|
+
assert_equal 'stdout', appender.name
|
26
|
+
assert_equal 2, appender.level
|
27
|
+
|
28
|
+
appender = Logging.appenders.stdout('bar', :level => :error)
|
29
|
+
assert_equal 'bar', appender.name
|
30
|
+
assert_equal 3, appender.level
|
31
|
+
end
|
32
|
+
|
33
|
+
end # class TestStdout
|
34
|
+
|
35
|
+
class TestStderr < Test::Unit::TestCase
|
36
|
+
include LoggingTestCase
|
37
|
+
|
38
|
+
def test_initialize
|
39
|
+
Logging::Repository.instance
|
40
|
+
|
41
|
+
appender = Logging.appenders.stderr
|
42
|
+
assert_equal 'stderr', appender.name
|
43
|
+
assert_same STDERR, appender.instance_variable_get(:@io)
|
44
|
+
|
45
|
+
appender.close
|
46
|
+
assert_equal true, appender.closed?
|
47
|
+
assert_equal false, STDERR.closed?
|
48
|
+
|
49
|
+
appender = Logging.appenders.stderr('foo')
|
50
|
+
assert_equal 'foo', appender.name
|
51
|
+
|
52
|
+
appender = Logging.appenders.stderr(:level => :warn)
|
53
|
+
assert_equal 'stderr', appender.name
|
54
|
+
assert_equal 2, appender.level
|
55
|
+
|
56
|
+
appender = Logging.appenders.stderr('bar', :level => :error)
|
57
|
+
assert_equal 'bar', appender.name
|
58
|
+
assert_equal 3, appender.level
|
59
|
+
end
|
60
|
+
|
61
|
+
end # class TestStderr
|
62
|
+
|
63
|
+
end # module TestAppenders
|
64
|
+
end # module TestLogging
|
65
|
+
|
66
|
+
# EOF
|