logging 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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