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.
@@ -1,5 +1,5 @@
1
1
  module Logging
2
- VERSION = "2.0.0".freeze
2
+ VERSION = "2.1.0".freeze
3
3
 
4
4
  # Returns the version string for the library.
5
5
  def self.version
@@ -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"]
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require "irb"
3
+ require "rubygems"
4
+
5
+ $LOAD_PATH.unshift "lib"
6
+ require "logging"
7
+
8
+ IRB.start
@@ -4,14 +4,15 @@ require File.expand_path('../setup', File.dirname(__FILE__))
4
4
  module TestLogging
5
5
  module TestAppenders
6
6
 
7
- class TestPeriodicFlushing < Test::Unit::TestCase
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', :flush_period => 2
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 test_periodic_flusher_running
46
- flusher = @appender.instance_variable_get(:@periodic_flusher)
47
- assert_instance_of Logging::Appenders::Buffering::PeriodicFlusher, flusher
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 periodic flusher should be waiting for a signal'
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
- private
133
- def readline
134
- @appender.readline
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
- end # class TestPeriodicFlushing
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
- end # module TestAppenders
140
- end # module TestLogging
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', :auto_flushing => 3, :immediate_at => :error
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
 
@@ -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
 
@@ -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.appenders.string_io(
26
- 'sio',
27
- :layout => Logging.layouts.pattern(
28
- :pattern => '%.1l, [%d] %5l -- %c: %m\n',
29
- :date_pattern => "%Y-%m-%dT%H:%M:%S.%s"
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('benchmark')
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
- x = ::Log4r::Logger.new('benchmark')
43
- x.level = ::Log4r::WARN
44
- x.add ::Log4r::IOOutputter.new(
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.\#{Time.now.usec}"
45
+ :date_pattern => "%Y-%m-%dT%H:%M:%S.%6N"
49
46
  )
50
47
  )
51
- x
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
- end # class Benchmark
82
- end # module Logging
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
-
@@ -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
@@ -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 'rubygems'
8
- require 'test/unit'
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
- require File.join(File.dirname(__FILE__), %w[.. lib logging])
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
- TMP = 'tmp'
18
+ TMP = 'tmp'
25
19
 
26
- def setup
27
- super
28
- Logging.reset
29
- FileUtils.rm_rf TMP
30
- FileUtils.mkdir TMP
31
- end
20
+ def setup
21
+ super
22
+ Logging.reset
23
+ FileUtils.rm_rf TMP
24
+ FileUtils.mkdir TMP
25
+ end
32
26
 
33
- def teardown
34
- super
35
- FileUtils.rm_rf TMP
27
+ def teardown
28
+ super
29
+ FileUtils.rm_rf TMP
30
+ end
36
31
  end
32
+ end
37
33
 
38
- end # LoggingTestCase
39
- end # TestLogging
40
-
41
- end # defined?
42
-
34
+ end