From 6b1239a8203a6150762eb8856c72771784b33bd0 Mon Sep 17 00:00:00 2001 From: nahi Date: Tue, 13 Sep 2005 13:13:41 +0000 Subject: [PATCH] * lib/logger.rb (Logger): added formatter accessor to logger for dictating the way in which the logger should format the messages it displays. Thanks to Nicholas Seckar (cf. [ruby-talk:153391]) and Daniel Berger. * lib/logger.rb (Logger): added VERSION constant. * lib/logger.rb: removed document for LogDevice. It is an implementation detail and is not a public interface. * test/logger/test_logger.rb: added tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9151 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 14 ++++ lib/logger.rb | 142 +++++++++++++++++-------------------- test/logger/test_logger.rb | 34 ++++++++- 3 files changed, 109 insertions(+), 81 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4d7dfe39b..47eab8a5e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Tue Sep 13 22:09:40 2005 NAKAMURA, Hiroshi + + * lib/logger.rb (Logger): added formatter accessor to logger for + dictating the way in which the logger should format the messages it + displays. Thanks to Nicholas Seckar (cf. [ruby-talk:153391]) and + Daniel Berger. + + * lib/logger.rb (Logger): added VERSION constant. + + * lib/logger.rb: removed document for LogDevice. It is an + implementation detail and is not a public interface. + + * test/logger/test_logger.rb: added tests. + Tue Sep 13 21:47:17 2005 Nobuyoshi Nakada * eval.c (BEGIN_CALLARGS): pop halfly pushed status. diff --git a/lib/logger.rb b/lib/logger.rb index 52e5a45684..9a2b51d6db 100644 --- a/lib/logger.rb +++ b/lib/logger.rb @@ -178,6 +178,7 @@ require 'monitor' class Logger + VERSION = "1.2.6" /: (\S+),v (\S+)/ =~ %q$Id$ ProgName = "#{$1}/#{$2}" @@ -202,7 +203,20 @@ class Logger attr_accessor :progname # Logging date-time format (string passed to +strftime+). - attr_accessor :datetime_format + def datetime_format=(datetime_format) + @default_formatter.datetime_format = datetime_format + end + + def datetime_format + @default_formatter.datetime_format + end + + # Logging formatter. formatter#call is invoked with 4 arguments; severity, + # time, progname and msg for each log. Bear in mind that time is a Time and + # msg is an Object that user passed and it could not be a String. It is + # expected to return a logdev#write-able Object. Default formatter is used + # when no formatter is set. + attr_accessor :formatter alias sev_threshold level alias sev_threshold= level= @@ -246,16 +260,17 @@ class Logger # # === Description # - # Create an instance. See Logger::LogDevice.new for more information if - # required. + # Create an instance. # def initialize(logdev, shift_age = 0, shift_size = 1048576) @progname = nil @level = DEBUG - @datetime_format = nil + @default_formatter = Formatter.new + @formatter = nil @logdev = nil if logdev - @logdev = LogDevice.new(logdev, :shift_age => shift_age, :shift_size => shift_size) + @logdev = LogDevice.new(logdev, :shift_age => shift_age, + :shift_size => shift_size) end end @@ -318,13 +333,7 @@ class Logger end end @logdev.write( - format_message( - format_severity(severity), - format_datetime(Time.now), - msg2str(message), - progname - ) - ) + format_message(format_severity(severity), Time.now, progname, message)) true end alias log add @@ -427,74 +436,60 @@ private SEV_LABEL[severity] || 'ANY' end - def format_datetime(datetime) - if @datetime_format.nil? - datetime.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % datetime.usec - else - datetime.strftime(@datetime_format) + def format_message(severity, datetime, progname, msg) + (@formatter || @default_formatter).call(severity, datetime, progname, msg) + end + + + class Formatter + Format = "%s, [%s#%d] %5s -- %s: %s\n" + + attr_accessor :datetime_format + + def initialize + @datetime_format = nil end - end - Format = "%s, [%s#%d] %5s -- %s: %s\n" - def format_message(severity, timestamp, msg, progname) - Format % [severity[0..0], timestamp, $$, severity, progname, msg] - end + def call(severity, time, progname, msg) + Format % [severity[0..0], format_datetime(time), $$, severity, progname, + msg2str(msg)] + end - def msg2str(msg) - case msg - when ::String - msg - when ::Exception - "#{ msg.message } (#{ msg.class })\n" << (msg.backtrace || []).join("\n") - else - msg.inspect + private + + def format_datetime(time) + if @datetime_format.nil? + time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec + else + time.strftime(@datetime_format) + end + end + + def msg2str(msg) + case msg + when ::String + msg + when ::Exception + "#{ msg.message } (#{ msg.class })\n" << + (msg.backtrace || []).join("\n") + else + msg.inspect + end end end - # - # LogDevice -- Logging device. - # class LogDevice attr_reader :dev attr_reader :filename - # - # == Synopsis - # - # Logger::LogDevice.new(name, :shift_age => 'daily|weekly|monthly') - # Logger::LogDevice.new(name, :shift_age => 10, :shift_size => 1024*1024) - # - # == Args - # - # +name+:: - # A String (representing a filename) or an IO object (actually, anything - # that responds to +write+ and +close+). If a filename is given, then - # that file is opened for writing (and appending if it already exists), - # with +sync+ set to +true+. - # +opts+:: - # Contains optional arguments for rolling ("shifting") the log file. - # :shift_age is either a description (e.g. 'daily'), or an - # integer number of log files to keep. shift_size is the maximum - # size of the log file, and is only significant is a number is given for - # shift_age. - # - # These arguments are only relevant if a filename is provided for the - # first argument. - # - # == Description - # - # Creates a LogDevice object, which is the target for log messages. Rolling - # of log files is supported (only if a filename is given; you can't roll an - # IO object). The beginning of each file created by this class is tagged - # with a header message. - # - # This class is unlikely to be used directly; it is a backend for Logger. - # + class LogDeviceMutex + include MonitorMixin + end + def initialize(log = nil, opt = {}) @dev = @filename = @shift_age = @shift_size = nil - @mutex = Object.new - @mutex.extend(MonitorMixin) + @mutex = LogDeviceMutex.new if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @@ -506,12 +501,6 @@ private end end - # - # Log a message. If needed, the log file is rolled and the new file is - # prepared. Log device is not locked. Append open does not need to lock - # file but on an OS which supports multi I/O, records could possibly be - # mixed. - # def write(message) @mutex.synchronize do if @shift_age and @dev.respond_to?(:stat) @@ -525,9 +514,6 @@ private end end - # - # Close the logging device. - # def close @mutex.synchronize do @dev.close @@ -689,8 +675,8 @@ private end # - # Sets the log device for this application. See the classes Logger and - # Logger::LogDevice for an explanation of the arguments. + # Sets the log device for this application. See the class Logger for an + # explanation of the arguments. # def set_log(logdev, shift_age = 0, shift_size = 1024000) @log = Logger.new(logdev, shift_age, shift_size) diff --git a/test/logger/test_logger.rb b/test/logger/test_logger.rb index 7f11a30a1f..6fba2bc7b6 100644 --- a/test/logger/test_logger.rb +++ b/test/logger/test_logger.rb @@ -36,13 +36,17 @@ class TestLogger < Test::Unit::TestCase end def log(logger, msg_id, *arg, &block) + Log.new(log_raw(logger, msg_id, *arg, &block)) + end + + def log_raw(logger, msg_id, *arg, &block) logdev = Tempfile.new(File.basename(__FILE__) + '.log') logger.instance_eval { @logdev = Logger::LogDevice.new(logdev) } logger.__send__(msg_id, *arg, &block) logdev.open msg = logdev.read logdev.close - Log.new(msg) + msg end def test_level @@ -98,6 +102,32 @@ class TestLogger < Test::Unit::TestCase assert_match(/^$/, log.datetime) end + def test_formatter + dummy = STDERR + logger = Logger.new(dummy) + # default + log = log(logger, :info, "foo") + assert_equal("foo\n", log.msg) + # config + logger.formatter = proc { |severity, timestamp, progname, msg| + "#{severity}:#{msg}\n\n" + } + line = log_raw(logger, :info, "foo") + assert_equal("INFO:foo\n\n", line) + # recover + logger.formatter = nil + log = log(logger, :info, "foo") + assert_equal("foo\n", log.msg) + # again + o = Object.new + def o.call(severity, timestamp, progname, msg) + "<<#{severity}-#{msg}>>\n" + end + logger.formatter = o + line = log_raw(logger, :info, "foo") + assert_equal("<>\n", line) + end + def test_initialize logger = Logger.new(STDERR) assert_nil(logger.progname) @@ -301,7 +331,6 @@ class TestLogDevice < Test::Unit::TestCase assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) - logger.close File.unlink(logfile) File.unlink(logfile0) File.unlink(logfile1) @@ -337,7 +366,6 @@ class TestLogDevice < Test::Unit::TestCase assert(!File.exist?(logfile3)) logger.error("0" * 15) assert(!File.exist?(logfile3)) - logger.close File.unlink(logfile) File.unlink(logfile0) File.unlink(logfile1)