summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--NEWS7
-rw-r--r--lib/logger.rb97
-rw-r--r--test/logger/test_logger.rb142
4 files changed, 218 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index b318bb93f5..6893ed8cee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Nov 24 23:53:44 2008 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/logger.rb: imported upstream version (logger/1.2.7)
+ * do not raise an exception even if log writing failed.
+ * do not raise ShiftingError if an aged file already exists.
+ (no ShiftingError will be raised from 1.2.7, just warn() instead)
+ * test/logger/test_logger.rb: ditto.
+
Mon Nov 24 23:47:22 2008 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
* time.c: RDoc typo fixed.
diff --git a/NEWS b/NEWS
index 8f08f09627..8d06ee8117 100644
--- a/NEWS
+++ b/NEWS
@@ -84,6 +84,13 @@ with all sufficient information, see the ChangeLog file.
http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/
+* logger
+
+ * imported upstream version (logger/1.2.7)
+ * do not raise an exception even if log writing failed.
+ * do not raise ShiftingError if an aged file already exists.
+ (no ShiftingError will be raised from 1.2.7, just warn() instead)
+
== Changes since the 1.8.6 release
=== Configuration changes
diff --git a/lib/logger.rb b/lib/logger.rb
index 15d95fcb10..46cc18a3f2 100644
--- a/lib/logger.rb
+++ b/lib/logger.rb
@@ -1,8 +1,12 @@
# logger.rb - simple logging utility
-# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
+# Copyright (C) 2000-2003, 2005, 2008 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
+
require 'monitor'
+
+# = logger.rb
+#
# Simple logging utility.
#
# Author:: NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>
@@ -12,6 +16,11 @@ require 'monitor'
# license; either the dual license version in 2003, or any later version.
# Revision:: $Id$
#
+# See Logger for documentation.
+#
+
+
+#
# == Description
#
# The Logger class provides a simple but sophisticated logging utility that
@@ -143,14 +152,14 @@ require 'monitor'
# 2. Log4r (somewhat) compatible interface.
#
# logger.level = Logger::INFO
-#
+#
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
#
#
# == Format
#
-# Log messages are rendered in the output stream in a certain format. The
-# default format and a sample are shown below:
+# Log messages are rendered in the output stream in a certain format by
+# default. The default format and a sample are shown below:
#
# Log format:
# SeverityID, [Date Time mSec #pid] SeverityLabel -- ProgName: message
@@ -163,18 +172,22 @@ require 'monitor'
# logger.datetime_format = "%Y-%m-%d %H:%M:%S"
# # e.g. "2004-01-03 00:54:26"
#
-# There is currently no supported way to change the overall format, but you may
-# have some luck hacking the Format constant.
+# You may change the overall format with Logger#formatter= method.
+#
+# logger.formatter = proc { |severity, datetime, progname, msg|
+# "#{datetime}: #{msg}\n"
+# }
+# # e.g. "Thu Sep 22 08:51:08 GMT+9:00 2005: hello world"
#
class Logger
- VERSION = "1.2.6"
- id, name, rev = %w$Id$
- ProgName = "#{name.chomp(",v")}/#{rev}"
+ VERSION = "1.2.7"
+ /: (\S+) (\S+)/ =~ %q$Id$
+ ProgName = "#{$1}/#{$2}"
class Error < RuntimeError; end
- class ShiftingError < Error; end
+ class ShiftingError < Error; end # not used after 1.2.7. just for compat.
# Logging severity.
module Severity
@@ -494,20 +507,27 @@ private
def write(message)
@mutex.synchronize do
- if @shift_age and @dev.respond_to?(:stat)
+ begin
+ if @shift_age and @dev.respond_to?(:stat)
+ begin
+ check_shift_log
+ rescue
+ warn("log shifting failed. #{$!}")
+ end
+ end
begin
- check_shift_log
+ @dev.write(message)
rescue
- raise Logger::ShiftingError.new("Shifting failed. #{$!}")
+ warn("log writing failed. #{$!}")
end
+ rescue Exception => ignored
end
- @dev.write(message)
end
end
def close
@mutex.synchronize do
- @dev.close
+ @dev.close rescue nil
end
end
@@ -530,8 +550,8 @@ private
def add_log_header(file)
file.write(
- "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
- )
+ "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
+ )
end
SiD = 24 * 60 * 60
@@ -544,8 +564,9 @@ private
end
else
now = Time.now
- if @dev.stat.mtime <= previous_period_end(now)
- shift_log_period(now)
+ period_end = previous_period_end(now)
+ if @dev.stat.mtime <= period_end
+ shift_log_period(period_end)
end
end
end
@@ -556,19 +577,26 @@ private
File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}")
end
end
- @dev.close
+ @dev.close rescue nil
File.rename("#{@filename}", "#{@filename}.0")
@dev = create_logfile(@filename)
return true
end
- def shift_log_period(now)
- postfix = previous_period_end(now).strftime("%Y%m%d") # YYYYMMDD
+ def shift_log_period(period_end)
+ postfix = period_end.strftime("%Y%m%d") # YYYYMMDD
age_file = "#{@filename}.#{postfix}"
if FileTest.exist?(age_file)
- raise RuntimeError.new("'#{ age_file }' already exists.")
+ # try to avoid filename crash caused by Timestamp change.
+ idx = 0
+ # .99 can be overriden; avoid too much file search with 'loop do'
+ while idx < 100
+ idx += 1
+ age_file = "#{@filename}.#{postfix}.#{idx}"
+ break unless FileTest.exist?(age_file)
+ end
end
- @dev.close
+ @dev.close rescue nil
File.rename("#{@filename}", age_file)
@dev = create_logfile(@filename)
return true
@@ -625,8 +653,8 @@ private
class Application
include Logger::Severity
+ # Name of the application given at initialize.
attr_reader :appname
- attr_reader :logdev
#
# == Synopsis
@@ -665,9 +693,23 @@ private
status
end
+ # Logger for this application. See the class Logger for an explanation.
+ def logger
+ @log
+ end
+
+ #
+ # Sets the logger for this application. See the class Logger for an explanation.
+ #
+ def logger=(logger)
+ @log = logger
+ @log.progname = @appname
+ @log.level = @level
+ end
+
#
- # Sets the log device for this application. See the class Logger for an
- # explanation of the arguments.
+ # Sets the log device for this application. See <tt>Logger.new</tt> for an explanation
+ # of the arguments.
#
def set_log(logdev, shift_age = 0, shift_size = 1024000)
@log = Logger.new(logdev, shift_age, shift_size)
@@ -697,6 +739,7 @@ private
private
def run
+ # TODO: should be an NotImplementedError
raise RuntimeError.new('Method run must be defined in the derived class.')
end
end
diff --git a/test/logger/test_logger.rb b/test/logger/test_logger.rb
index 5969854976..bb9f997666 100644
--- a/test/logger/test_logger.rb
+++ b/test/logger/test_logger.rb
@@ -21,10 +21,13 @@ class TestLogger < Test::Unit::TestCase
def setup
@logger = Logger.new(nil)
+ @filename = __FILE__ + ".#{$$}"
end
- def test_const_progname
- assert %r!\Alogger\.rb/\S+\z! === Logger::ProgName
+ def teardown
+ unless $DEBUG
+ File.unlink(@filename) if File.exist?(@filename)
+ end
end
class Log
@@ -262,8 +265,31 @@ class TestLogger < Test::Unit::TestCase
end
class TestLogDevice < Test::Unit::TestCase
- def d(log)
- Logger::LogDevice.new(log)
+ class LogExcnRaiser
+ def write(*arg)
+ raise 'disk is full'
+ end
+
+ def close
+ end
+
+ def stat
+ Object.new
+ end
+ end
+
+ def setup
+ @filename = __FILE__ + ".#{$$}"
+ end
+
+ def teardown
+ unless $DEBUG
+ File.unlink(@filename) if File.exist?(@filename)
+ end
+ end
+
+ def d(log, opt = {})
+ Logger::LogDevice.new(log, opt)
end
def test_initialize
@@ -274,16 +300,21 @@ class TestLogDevice < Test::Unit::TestCase
d(nil)
end
#
- filename = __FILE__ + ".#{$$}"
+ logdev = d(@filename)
begin
- logdev = d(filename)
- assert(File.exist?(filename))
+ assert(File.exist?(@filename))
assert(logdev.dev.sync)
- assert_equal(filename, logdev.filename)
+ assert_equal(@filename, logdev.filename)
+ logdev.write('hello')
ensure
logdev.close
- File.unlink(filename)
end
+ # create logfile whitch is already exist.
+ logdev = d(@filename)
+ logdev.write('world')
+ logfile = File.read(@filename)
+ assert_equal(2, logfile.split(/\n/).size)
+ assert_match(/^helloworld$/, logfile)
end
def test_write
@@ -295,6 +326,15 @@ class TestLogDevice < Test::Unit::TestCase
msg = r.read
r.close
assert_equal("msg2\n\n", msg)
+ #
+ logdev = d(LogExcnRaiser.new)
+ begin
+ assert_nothing_raised do
+ logdev.write('hello')
+ end
+ ensure
+ logdev.close
+ end
end
def test_close
@@ -377,4 +417,88 @@ class TestLogDevice < Test::Unit::TestCase
File.unlink(logfile1)
File.unlink(logfile2)
end
+
+ def test_shifting_age_variants
+ logger = Logger.new(@filename, 'daily')
+ logger.info('daily')
+ logger.close
+ logger = Logger.new(@filename, 'weekly')
+ logger.info('weekly')
+ logger.close
+ logger = Logger.new(@filename, 'monthly')
+ logger.info('monthly')
+ logger.close
+ end
+
+ def test_shifting_age
+ # shift_age other than 'daily', 'weekly', and 'monthly' means 'everytime'
+ yyyymmdd = Time.now.strftime("%Y%m%d")
+ filename1 = @filename + ".#{yyyymmdd}"
+ filename2 = @filename + ".#{yyyymmdd}.1"
+ filename3 = @filename + ".#{yyyymmdd}.2"
+ begin
+ logger = Logger.new(@filename, 'now')
+ assert(File.exist?(@filename))
+ assert(!File.exist?(filename1))
+ assert(!File.exist?(filename2))
+ assert(!File.exist?(filename3))
+ logger.info("0" * 15)
+ assert(File.exist?(@filename))
+ assert(File.exist?(filename1))
+ assert(!File.exist?(filename2))
+ assert(!File.exist?(filename3))
+ logger.warn("0" * 15)
+ assert(File.exist?(@filename))
+ assert(File.exist?(filename1))
+ assert(File.exist?(filename2))
+ assert(!File.exist?(filename3))
+ logger.error("0" * 15)
+ assert(File.exist?(@filename))
+ assert(File.exist?(filename1))
+ assert(File.exist?(filename2))
+ assert(File.exist?(filename3))
+ ensure
+ [filename1, filename2, filename3].each do |filename|
+ File.unlink(filename) if File.exist?(filename)
+ end
+ end
+ end
+end
+
+
+class TestLoggerApplication < Test::Unit::TestCase
+ def setup
+ @app = Logger::Application.new('appname')
+ @filename = __FILE__ + ".#{$$}"
+ end
+
+ def teardown
+ unless $DEBUG
+ File.unlink(@filename) if File.exist?(@filename)
+ end
+ end
+
+ def test_initialize
+ app = Logger::Application.new('appname')
+ assert_equal('appname', app.appname)
+ end
+
+ def test_start
+ @app.set_log(@filename)
+ @app.level = Logger::UNKNOWN
+ @app.start # logs FATAL log
+ assert_equal(1, File.read(@filename).split(/\n/).size)
+ end
+
+ def test_logger
+ @app.level = Logger::WARN
+ @app.set_log(@filename)
+ assert_equal(Logger::WARN, @app.logger.level)
+ @app.logger = logger = Logger.new(STDOUT)
+ assert_equal(logger, @app.logger)
+ assert_equal(Logger::WARN, @app.logger.level)
+ @app.log = @filename
+ assert(logger != @app.logger)
+ assert_equal(Logger::WARN, @app.logger.level)
+ end
end