logging 2.0.0 → 2.1.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/History.txt +19 -0
- data/Rakefile +1 -1
- data/examples/rails4.rb +21 -0
- data/lib/logging/appender.rb +6 -7
- data/lib/logging/appenders/buffering.rb +127 -56
- data/lib/logging/appenders/console.rb +36 -55
- data/lib/logging/appenders/file.rb +1 -1
- data/lib/logging/appenders/io.rb +10 -7
- data/lib/logging/appenders/rolling_file.rb +2 -2
- data/lib/logging/appenders/syslog.rb +1 -1
- data/lib/logging/diagnostic_context.rb +5 -3
- data/lib/logging/layout.rb +21 -8
- data/lib/logging/layouts/pattern.rb +3 -6
- data/lib/logging/log_event.rb +1 -1
- data/lib/logging/logger.rb +109 -89
- data/lib/logging/version.rb +1 -1
- data/logging.gemspec +1 -0
- data/script/console +8 -0
- data/test/appenders/{test_periodic_flushing.rb → test_async_flushing.rb} +67 -14
- data/test/appenders/test_buffered_io.rb +6 -3
- data/test/appenders/test_console.rb +8 -0
- data/test/appenders/test_file.rb +11 -6
- data/test/appenders/test_rolling_file.rb +6 -0
- data/test/appenders/test_syslog.rb +6 -0
- data/test/benchmark.rb +42 -18
- data/test/performance.rb +66 -0
- data/test/setup.rb +20 -28
- data/test/test_appender.rb +2 -4
- data/test/test_layout.rb +9 -0
- data/test/test_logger.rb +20 -3
- metadata +11 -8
data/lib/logging/version.rb
CHANGED
data/logging.gemspec
CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Tim Pease"]
|
11
11
|
s.date = "2015-03-29"
|
12
|
+
s.license = "MIT"
|
12
13
|
s.description = "Logging is a flexible logging library for use in Ruby programs based on the\ndesign of Java's log4j library. It features a hierarchical logging system,\ncustom level names, multiple output destinations per log event, custom\nformatting, and more."
|
13
14
|
s.email = "tim.pease@gmail.com"
|
14
15
|
s.extra_rdoc_files = ["History.txt"]
|
data/script/console
ADDED
@@ -4,14 +4,15 @@ require File.expand_path('../setup', File.dirname(__FILE__))
|
|
4
4
|
module TestLogging
|
5
5
|
module TestAppenders
|
6
6
|
|
7
|
-
class
|
7
|
+
class TestAsyncFlushing < Test::Unit::TestCase
|
8
8
|
include LoggingTestCase
|
9
9
|
|
10
10
|
def setup
|
11
11
|
super
|
12
|
-
@appender = Logging.appenders.string_io
|
13
|
-
'test_appender',
|
14
|
-
|
12
|
+
@appender = Logging.appenders.string_io \
|
13
|
+
'test_appender',
|
14
|
+
:flush_period => 2
|
15
|
+
|
15
16
|
@appender.clear
|
16
17
|
@sio = @appender.sio
|
17
18
|
@levels = Logging::LEVELS
|
@@ -42,12 +43,12 @@ module TestAppenders
|
|
42
43
|
assert_equal 200, @appender.auto_flushing
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
-
flusher = @appender.instance_variable_get(:@
|
47
|
-
assert_instance_of Logging::Appenders::Buffering::
|
46
|
+
def test_async_flusher_running
|
47
|
+
flusher = @appender.instance_variable_get(:@async_flusher)
|
48
|
+
assert_instance_of Logging::Appenders::Buffering::AsyncFlusher, flusher
|
48
49
|
|
49
50
|
sleep 0.250 # give the flusher thread another moment to start
|
50
|
-
assert flusher.waiting?, 'the
|
51
|
+
assert flusher.waiting?, 'the async flusher should be waiting for a signal'
|
51
52
|
end
|
52
53
|
|
53
54
|
def test_append
|
@@ -129,13 +130,65 @@ module TestAppenders
|
|
129
130
|
assert_nil(readline)
|
130
131
|
end
|
131
132
|
|
132
|
-
|
133
|
-
|
134
|
-
|
133
|
+
def test_setting_flush_period_to_nil
|
134
|
+
flusher = @appender.instance_variable_get(:@async_flusher)
|
135
|
+
assert_instance_of Logging::Appenders::Buffering::AsyncFlusher, flusher
|
136
|
+
|
137
|
+
@appender.flush_period = nil
|
138
|
+
|
139
|
+
assert_nil @appender.instance_variable_get(:@async_flusher)
|
135
140
|
end
|
136
141
|
|
137
|
-
|
142
|
+
def test_setting_negative_flush_period
|
143
|
+
assert_raise(ArgumentError) { @appender.flush_period = -1 }
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_async_writes
|
147
|
+
@appender.auto_flushing = 3
|
148
|
+
@appender.flush_period = nil
|
149
|
+
@appender.async = true
|
150
|
+
|
151
|
+
event = Logging::LogEvent.new('TestLogger', @levels['warn'],
|
152
|
+
[1, 2, 3, 4], false)
|
153
|
+
|
154
|
+
flusher = @appender.instance_variable_get(:@async_flusher)
|
155
|
+
assert_instance_of Logging::Appenders::Buffering::AsyncFlusher, flusher
|
138
156
|
|
139
|
-
|
140
|
-
|
157
|
+
@appender.append event
|
158
|
+
assert_nil(readline)
|
141
159
|
|
160
|
+
event.level = @levels['debug']
|
161
|
+
event.data = 'the big log message'
|
162
|
+
@appender.append event
|
163
|
+
sleep 0.250
|
164
|
+
assert_nil(readline)
|
165
|
+
|
166
|
+
event.level = @levels['info']
|
167
|
+
event.data = 'just FYI'
|
168
|
+
@appender.append event # might write here, might not
|
169
|
+
sleep 0.250 # so sleep a little to let the write occur
|
170
|
+
|
171
|
+
assert_equal " WARN TestLogger : <Array> #{[1, 2, 3, 4]}\n", readline
|
172
|
+
assert_equal "DEBUG TestLogger : the big log message\n", readline
|
173
|
+
assert_equal " INFO TestLogger : just FYI\n", readline
|
174
|
+
|
175
|
+
event.level = @levels['warn']
|
176
|
+
event.data = 'this is your last warning!'
|
177
|
+
@appender.append event
|
178
|
+
assert_nil(readline)
|
179
|
+
|
180
|
+
@appender.close_method = :close_write
|
181
|
+
@appender.close
|
182
|
+
|
183
|
+
assert_equal " WARN TestLogger : this is your last warning!\n", readline
|
184
|
+
|
185
|
+
assert_nil @appender.instance_variable_get(:@async_flusher)
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
def readline
|
190
|
+
@appender.readline
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -10,9 +10,12 @@ module TestAppenders
|
|
10
10
|
|
11
11
|
def setup
|
12
12
|
super
|
13
|
-
@appender = Logging.appenders.string_io
|
14
|
-
'test_appender',
|
15
|
-
|
13
|
+
@appender = Logging.appenders.string_io \
|
14
|
+
'test_appender',
|
15
|
+
:auto_flushing => 3,
|
16
|
+
:immediate_at => :error,
|
17
|
+
:encoding => 'UTF-8'
|
18
|
+
|
16
19
|
@appender.clear
|
17
20
|
@sio = @appender.sio
|
18
21
|
@levels = Logging::LEVELS
|
@@ -4,6 +4,14 @@ require File.expand_path('../setup', File.dirname(__FILE__))
|
|
4
4
|
module TestLogging
|
5
5
|
module TestAppenders
|
6
6
|
|
7
|
+
class TestConsole < Test::Unit::TestCase
|
8
|
+
include LoggingTestCase
|
9
|
+
|
10
|
+
def test_initialize
|
11
|
+
assert_raise(RuntimeError) { Logging::Appenders::Console.new("test") }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
7
15
|
class TestStdout < Test::Unit::TestCase
|
8
16
|
include LoggingTestCase
|
9
17
|
|
data/test/appenders/test_file.rb
CHANGED
@@ -20,24 +20,30 @@ module TestAppenders
|
|
20
20
|
FileUtils.chmod 0444, File.join(TMP, 'uw_file')
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_factory_method_validates_input
|
24
|
+
assert_raise(ArgumentError) do
|
25
|
+
Logging.appenders.file
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
23
29
|
def test_class_assert_valid_logfile
|
24
30
|
log = File.join(TMP, 'uw_dir', 'file.log')
|
25
31
|
assert_raise(ArgumentError) do
|
26
|
-
Logging.appenders.file.assert_valid_logfile(log)
|
32
|
+
Logging.appenders.file(log).class.assert_valid_logfile(log)
|
27
33
|
end
|
28
34
|
|
29
35
|
log = File.join(TMP, 'dir')
|
30
36
|
assert_raise(ArgumentError) do
|
31
|
-
Logging.appenders.file.assert_valid_logfile(log)
|
37
|
+
Logging.appenders.file(log).class.assert_valid_logfile(log)
|
32
38
|
end
|
33
39
|
|
34
40
|
log = File.join(TMP, 'uw_file')
|
35
41
|
assert_raise(ArgumentError) do
|
36
|
-
Logging.appenders.file.assert_valid_logfile(log)
|
42
|
+
Logging.appenders.file(log).class.assert_valid_logfile(log)
|
37
43
|
end
|
38
44
|
|
39
45
|
log = File.join(TMP, 'file.log')
|
40
|
-
assert Logging.appenders.file.assert_valid_logfile(log)
|
46
|
+
assert Logging.appenders.file(log).class.assert_valid_logfile(log)
|
41
47
|
end
|
42
48
|
|
43
49
|
def test_initialize
|
@@ -100,14 +106,13 @@ module TestAppenders
|
|
100
106
|
|
101
107
|
def test_encoding
|
102
108
|
log = File.join(TMP, 'file-encoding.log')
|
103
|
-
#appender = Logging.appenders.file(NAME, :filename => log, :encoding => 'ISO-8859-16')
|
104
109
|
appender = Logging.appenders.file(NAME, :filename => log, :encoding => 'ASCII')
|
105
110
|
|
106
111
|
appender << "A normal line of text\n"
|
107
112
|
appender << "ümlaut\n"
|
108
113
|
appender.close
|
109
114
|
|
110
|
-
lines = File.readlines(log)
|
115
|
+
lines = File.readlines(log, :encoding => 'UTF-8')
|
111
116
|
assert_equal "A normal line of text\n", lines[0]
|
112
117
|
assert_equal "ümlaut\n", lines[1]
|
113
118
|
|
@@ -18,6 +18,12 @@ module TestAppenders
|
|
18
18
|
@glob = File.expand_path('*.log', TMP)
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_factory_method_validates_input
|
22
|
+
assert_raise(ArgumentError) do
|
23
|
+
Logging.appenders.rolling_file
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
21
27
|
def test_initialize
|
22
28
|
assert_equal [], Dir.glob(@glob)
|
23
29
|
|
@@ -19,6 +19,12 @@ module TestAppenders
|
|
19
19
|
@logopt |= ::Syslog::LOG_PERROR if defined?(::Syslog::LOG_PERROR)
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_factory_method_validates_input
|
23
|
+
assert_raise(ArgumentError) do
|
24
|
+
Logging.appenders.syslog
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
22
28
|
def test_append
|
23
29
|
return if RUBY_PLATFORM =~ %r/cygwin|java/i
|
24
30
|
|
data/test/benchmark.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
require 'rubygems'
|
3
2
|
|
4
3
|
libpath = File.expand_path('../../lib', __FILE__)
|
@@ -22,16 +21,14 @@ module Logging
|
|
22
21
|
def run
|
23
22
|
this_many = 300_000
|
24
23
|
|
25
|
-
Logging.
|
26
|
-
'
|
27
|
-
:
|
28
|
-
|
29
|
-
|
30
|
-
)
|
31
|
-
)
|
24
|
+
pattern = Logging.layouts.pattern \
|
25
|
+
:pattern => '%.1l, [%d #%p] %5l -- %c: %m\n',
|
26
|
+
:date_pattern => "%Y-%m-%dT%H:%M:%S.%s"
|
27
|
+
|
28
|
+
Logging.appenders.string_io('sio', :layout => pattern)
|
32
29
|
sio = Logging.appenders['sio'].sio
|
33
30
|
|
34
|
-
logging = ::Logging.logger
|
31
|
+
logging = ::Logging.logger['benchmark']
|
35
32
|
logging.level = :warn
|
36
33
|
logging.appenders = 'sio'
|
37
34
|
|
@@ -39,16 +36,16 @@ module Logging
|
|
39
36
|
logger.level = ::Logger::WARN
|
40
37
|
|
41
38
|
log4r = if $log4r
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
l4r = ::Log4r::Logger.new('benchmark')
|
40
|
+
l4r.level = ::Log4r::WARN
|
41
|
+
l4r.add ::Log4r::IOOutputter.new(
|
45
42
|
'benchmark', sio,
|
46
43
|
:formatter => ::Log4r::PatternFormatter.new(
|
47
44
|
:pattern => "%.1l, [%d #\#{Process.pid}] %5l : %M\n",
|
48
|
-
:date_pattern => "%Y-%m-%dT%H:%M:%S
|
45
|
+
:date_pattern => "%Y-%m-%dT%H:%M:%S.%6N"
|
49
46
|
)
|
50
47
|
)
|
51
|
-
|
48
|
+
l4r
|
52
49
|
end
|
53
50
|
|
54
51
|
puts "== Debug (not logged) ==\n"
|
@@ -76,14 +73,41 @@ module Logging
|
|
76
73
|
bm.report('Logger:') {this_many.times {logger << 'logged'}}
|
77
74
|
puts "Log4r: not supported" if log4r
|
78
75
|
end
|
79
|
-
end
|
80
76
|
|
81
|
-
|
82
|
-
|
77
|
+
write_size = 250
|
78
|
+
auto_flushing_size = 500
|
79
|
+
|
80
|
+
logging_async = ::Logging.logger['AsyncFile']
|
81
|
+
logging_async.level = :info
|
82
|
+
logging_async.appenders = Logging.appenders.file \
|
83
|
+
'benchmark_async.log',
|
84
|
+
:layout => pattern,
|
85
|
+
:write_size => write_size,
|
86
|
+
:auto_flushing => auto_flushing_size,
|
87
|
+
:async => true
|
88
|
+
|
89
|
+
logging_sync = ::Logging.logger['SyncFile']
|
90
|
+
logging_sync.level = :info
|
91
|
+
logging_sync.appenders = Logging.appenders.file \
|
92
|
+
'benchmark_sync.log',
|
93
|
+
:layout => pattern,
|
94
|
+
:write_size => write_size,
|
95
|
+
:auto_flushing => auto_flushing_size,
|
96
|
+
:async => false
|
97
|
+
|
98
|
+
puts "\n== File ==\n"
|
99
|
+
::Benchmark.bm(20) do |bm|
|
100
|
+
bm.report('Logging (Async):') {this_many.times { |n| logging_async.info "Iteration #{n}"}}
|
101
|
+
bm.report('Logging (Sync):') {this_many.times { |n| logging_sync.info "Iteration #{n}"}}
|
102
|
+
end
|
83
103
|
|
104
|
+
File.delete('benchmark_async.log')
|
105
|
+
File.delete('benchmark_sync.log')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
84
109
|
|
85
110
|
if __FILE__ == $0
|
86
111
|
bm = ::Logging::Benchmark.new
|
87
112
|
bm.run
|
88
113
|
end
|
89
|
-
|
data/test/performance.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# The peformance script is used to output a performance analysis page for the
|
3
|
+
# Logging framework. You can run this script simply:
|
4
|
+
#
|
5
|
+
# ruby test/performance.rb
|
6
|
+
#
|
7
|
+
# This will write a file called "performance.html" that you can open in your web
|
8
|
+
# browser. You will need the `ruby-prof` gem installed in order to run this
|
9
|
+
# script.
|
10
|
+
# ------------------------------------------------------------------------------
|
11
|
+
require 'rubygems'
|
12
|
+
|
13
|
+
libpath = File.expand_path('../../lib', __FILE__)
|
14
|
+
$:.unshift libpath
|
15
|
+
require 'logging'
|
16
|
+
|
17
|
+
begin
|
18
|
+
gem 'log4r'
|
19
|
+
require 'log4r'
|
20
|
+
$log4r = true
|
21
|
+
rescue LoadError
|
22
|
+
$log4r = false
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'logger'
|
26
|
+
require 'ruby-prof'
|
27
|
+
|
28
|
+
module Logging
|
29
|
+
class Performance
|
30
|
+
|
31
|
+
# number of iterations
|
32
|
+
attr_reader :this_many
|
33
|
+
|
34
|
+
# performance output file name
|
35
|
+
attr_reader :output_file
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@this_many = 300_000
|
39
|
+
@output_file = "performance.html"
|
40
|
+
end
|
41
|
+
|
42
|
+
def run
|
43
|
+
pattern = Logging.layouts.pattern \
|
44
|
+
:pattern => '%.1l, [%d#%p] %5l -- %c: %m\n',
|
45
|
+
:date_pattern => "%Y-%m-%dT%H:%M:%S.%s"
|
46
|
+
|
47
|
+
Logging.appenders.string_io("sio", :layout => pattern)
|
48
|
+
|
49
|
+
logger = ::Logging.logger["Performance"]
|
50
|
+
logger.level = :warn
|
51
|
+
logger.appenders = "sio"
|
52
|
+
|
53
|
+
result = RubyProf.profile do
|
54
|
+
this_many.times {logger.warn 'logged'}
|
55
|
+
end
|
56
|
+
|
57
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
58
|
+
File.open(output_file, "w") { |fd| printer.print(fd) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if __FILE__ == $0
|
64
|
+
perf = Logging::Performance.new
|
65
|
+
perf.run
|
66
|
+
end
|
data/test/setup.rb
CHANGED
@@ -1,42 +1,34 @@
|
|
1
|
-
|
2
1
|
# Equivalent to a header guard in C/C++
|
3
2
|
# Used to prevent the class/module from being loaded more than once
|
4
3
|
unless defined? LOGGING_TEST_SETUP
|
5
4
|
LOGGING_TEST_SETUP = true
|
6
5
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
begin
|
10
|
-
require 'turn'
|
11
|
-
rescue LoadError; end
|
12
|
-
|
13
|
-
# This line is needed for Ruby 1.9 -- hashes throw a "KeyError" in 1.9
|
14
|
-
# whereas they throw an "IndexError" in 1.8
|
15
|
-
#
|
16
|
-
KeyError = IndexError if not defined? KeyError
|
6
|
+
require "rubygems"
|
7
|
+
require "test/unit"
|
17
8
|
|
18
|
-
|
9
|
+
if Test::Unit::TestCase.respond_to? :test_order=
|
10
|
+
Test::Unit::TestCase.test_order = :random
|
11
|
+
end
|
19
12
|
|
13
|
+
require File.expand_path("../../lib/logging", __FILE__)
|
20
14
|
|
21
15
|
module TestLogging
|
22
|
-
module LoggingTestCase
|
16
|
+
module LoggingTestCase
|
23
17
|
|
24
|
-
|
18
|
+
TMP = 'tmp'
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
def setup
|
21
|
+
super
|
22
|
+
Logging.reset
|
23
|
+
FileUtils.rm_rf TMP
|
24
|
+
FileUtils.mkdir TMP
|
25
|
+
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
def teardown
|
28
|
+
super
|
29
|
+
FileUtils.rm_rf TMP
|
30
|
+
end
|
36
31
|
end
|
32
|
+
end
|
37
33
|
|
38
|
-
end
|
39
|
-
end # TestLogging
|
40
|
-
|
41
|
-
end # defined?
|
42
|
-
|
34
|
+
end
|