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 + + * 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 * 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 . +# Copyright (C) 2000-2003, 2005, 2008 NAKAMURA, Hiroshi . + require 'monitor' + +# = logger.rb +# # Simple logging utility. # # Author:: NAKAMURA, Hiroshi @@ -11,6 +15,11 @@ require 'monitor' # You can redistribute it and/or modify it under the same terms of Ruby's # license; either the dual license version in 2003, or any later version. # Revision:: $Id$ +# +# See Logger for documentation. +# + + # # == Description # @@ -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 - check_shift_log - rescue - raise Logger::ShiftingError.new("Shifting failed. #{$!}") + begin + if @shift_age and @dev.respond_to?(:stat) + begin + check_shift_log + rescue + warn("log shifting failed. #{$!}") + end end + begin + @dev.write(message) + rescue + 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 log device for this application. See the class Logger for an - # explanation of the arguments. + # 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 Logger.new 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