diff options
Diffstat (limited to 'lib/logger.rb')
| -rw-r--r-- | lib/logger.rb | 595 |
1 files changed, 0 insertions, 595 deletions
diff --git a/lib/logger.rb b/lib/logger.rb deleted file mode 100644 index e8e163ca93..0000000000 --- a/lib/logger.rb +++ /dev/null @@ -1,595 +0,0 @@ -# Logger -- Logging utility. -# -# $Id$ -# -# This module is copyrighted free software by NAKAMURA, Hiroshi. -# You can redistribute it and/or modify it under the same term as Ruby. -# -# See Logger at first. - - -# DESCRIPTION -# Logger -- Logging utility. -# -# How to create a logger. -# 1. Create logger which logs messages to STDERR/STDOUT. -# logger = Logger.new(STDERR) -# logger = Logger.new(STDOUT) -# -# 2. Create logger for the file which has the specified name. -# logger = Logger.new('logfile.log') -# -# 3. Create logger for the specified file. -# file = open('foo.log', File::WRONLY | File::APPEND) -# # To create new (and to remove old) logfile, add File::CREAT like; -# # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT) -# logger = Logger.new(file) -# -# 4. Create logger which ages logfile automatically. Leave 10 ages and each -# file is about 102400 bytes. -# logger = Logger.new('foo.log', 10, 102400) -# -# 5. Create logger which ages logfile daily/weekly/monthly automatically. -# logger = Logger.new('foo.log', 'daily') -# logger = Logger.new('foo.log', 'weekly') -# logger = Logger.new('foo.log', 'monthly') -# -# How to log a message. -# -# 1. Message in block. -# logger.fatal { "Argument 'foo' not given." } -# -# 2. Message as a string. -# logger.error "Argument #{ @foo } mismatch." -# -# 3. With progname. -# logger.info('initialize') { "Initializing..." } -# -# 4. With severity. -# logger.add(Logger::FATAL) { 'Fatal error!' } -# -# How to close a logger. -# -# logger.close -# -# Setting severity threshold. -# -# 1. Original interface. -# logger.level = Logger::WARN -# -# 2. Log4r (somewhat) compatible interface. -# logger.level = Logger::INFO -# -# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN -# -# Format. -# -# Log format: -# SeverityID, [Date Time mSec #pid] SeverityLabel -- ProgName: message -# -# Log sample: -# I, [Wed Mar 03 02:34:24 JST 1999 895701 #19074] INFO -- Main: info. -# -class Logger - /: (\S+),v (\S+)/ =~ %q$Id$ - ProgName = "#{$1}/#{$2}" - - class Error < RuntimeError; end - class ShiftingError < Error; end - - # Logging severity. - module Severity - DEBUG = 0 - INFO = 1 - WARN = 2 - ERROR = 3 - FATAL = 4 - UNKNOWN = 5 - end - include Severity - - # Logging severity threshold. - attr_accessor :level - - # Logging program name. - attr_accessor :progname - - # Logging date-time format (string passed to strftime) - attr_accessor :datetime_format - - alias sev_threshold level - alias sev_threshold= level= - - def debug?; @level <= DEBUG; end - def info?; @level <= INFO; end - def warn?; @level <= WARN; end - def error?; @level <= ERROR; end - def fatal?; @level <= FATAL; end - - # SYNOPSIS - # Logger.new(name, shift_age = 7, shift_size = 1048576) - # - # ARGS - # log String as filename of logging. - # or - # IO as logging device(i.e. STDERR). - # shift_age An Integer Num of files you want to keep aged logs. - # 'daily' Daily shifting. - # 'weekly' Weekly shifting (Every monday.) - # 'monthly' Monthly shifting (Every 1th day.) - # shift_size Shift size threshold when shift_age is an integer. - # Otherwise (like 'daily'), shift_size will be ignored. - # - # DESCRIPTION - # Create an instance. - # - def initialize(logdev, shift_age = 0, shift_size = 1048576) - @logdev = nil - @progname = nil - @level = DEBUG - @datetime_format = nil - @logdev = nil - if logdev - @logdev = LogDevice.new(logdev, :shift_age => shift_age, :shift_size => shift_size) - end - end - - # SYNOPSIS - # Logger#add(severity, msg = nil, progname = nil) { ... } = nil - # - # ARGS - # severity Severity. Constants are defined in Logger namespace. - # DEBUG, INFO, WARN, ERROR, FATAL, or UNKNOWN. - # msg Message. A string, exception, or something. Can be omitted. - # progname Program name string. Can be omitted. - # Logged as a msg if no msg and block are given. - # block Can be omitted. - # Called to get a message string if msg is nil. - # - # RETURN - # true if succeed, false if failed. - # When the given severity is not enough severe, - # Log no message, and returns true. - # - # DESCRIPTION - # Log a log if the given severity is enough severe. - # - # BUGS - # Logfile is not locked. - # Append open does not need to lock file. - # But on the OS which supports multi I/O, records possibly be mixed. - # - def add(severity, msg = nil, progname = nil, &block) - severity ||= UNKNOWN - if @logdev.nil? or severity < @level - return true - end - progname ||= @progname - if msg.nil? - if block_given? - msg = yield - else - msg = progname - progname = @progname - end - end - @logdev.write( - format_message( - format_severity(severity), - format_datetime(Time.now), - msg2str(msg), - progname - ) - ) - true - end - alias log add - - # SYNOPSIS - # Logger#<<(msg) - # - # ARGS - # msg Message. - # - # RETURN - # Same as IO#<<. If logdev is not given, returns nil. - # - # DESCRIPTION - # Dump given message to log device without any formatting. - # - def <<(msg) - unless @logdev.nil? - @logdev.write(msg) - end - end - - # SYNOPSIS - # Logger#debug(progname = nil) { ... } = nil - # Logger#info(progname = nil) { ... } = nil - # Logger#warn(progname = nil) { ... } = nil - # Logger#error(progname = nil) { ... } = nil - # Logger#fatal(progname = nil) { ... } = nil - # Logger#unknown(progname = nil) { ... } = nil - # - # ARGS - # progname Program name string. Can be omitted. - # Logged as a msg if no block are given. - # block Can be omitted. - # Called to get a message string if msg is nil. - # - # RETURN - # See Logger#add . - # - # DESCRIPTION - # Log a log. - # - def debug(progname = nil, &block) - add(DEBUG, nil, progname, &block) - end - - def info(progname = nil, &block) - add(INFO, nil, progname, &block) - end - - def warn(progname = nil, &block) - add(WARN, nil, progname, &block) - end - - def error(progname = nil, &block) - add(ERROR, nil, progname, &block) - end - - def fatal(progname = nil, &block) - add(FATAL, nil, progname, &block) - end - - def unknown(progname = nil, &block) - add(UNKNOWN, nil, progname, &block) - end - - # SYNOPSIS - # Logger#close - # - # DESCRIPTION - # Close the logging device. - # - def close - @logdev.close if @logdev - end - -private - - # Severity label for logging. (max 5 char) - SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY); - - def format_severity(severity) - SEV_LABEL[severity] || 'ANY' - end - - def format_datetime(datetime) - if @datetime_format.nil? - datetime.strftime("%Y-%m-%dT%H:%M:%S.") << "%6d " % datetime.usec - else - datetime.strftime(@datetime_format) - 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 msg2str(msg) - if msg.is_a?(::String) - msg - elsif msg.is_a?(::Exception) - "#{ msg.message } (#{ msg.class })\n" << (msg.backtrace || []).join("\n") - elsif msg.respond_to?(:to_str) - msg.to_str - else - msg.inspect - end - end - - - # LogDevice -- Logging device. - class LogDevice - attr_reader :dev - attr_reader :filename - - # SYNOPSIS - # Logger::LogDev.new(name, opt = {}) - # - # ARGS - # log String as filename of logging. - # or - # IO as logging device(i.e. STDERR). - # opt Hash of options. - # - # DESCRIPTION - # Log device class. Output and shifting of log. - # When a String was given, LogDevice opens the file and set sync = true. - # - # OPTIONS - # :shift_age - # An Integer Num of files you want to keep aged logs. - # 'daily' Daily shifting. - # 'weekly' Weekly shifting (Shift every monday.) - # 'monthly' Monthly shifting (Shift every 1th day.) - # - # :shift_size Shift size threshold when :shift_age is an integer. - # Otherwise (like 'daily'), it is ignored. - # - def initialize(log = nil, opt = {}) - @dev = @filename = @shift_age = @shift_size = nil - if log.respond_to?(:write) and log.respond_to?(:close) - @dev = log - elsif log.is_a?(String) - @dev = open_logfile(log) - @dev.sync = true - @filename = log - @shift_age = opt[:shift_age] || 7 - @shift_size = opt[:shift_size] || 1048576 - else - raise ArgumentError.new("Wrong argument: #{ log } for log.") - end - end - - # SYNOPSIS - # Logger::LogDev#write(message) - # - # ARGS - # message Message to be logged. - # - # DESCRIPTION - # Log a message. If needed, the log device is aged and the new device - # is prepared. Log device is not locked. Append open does not need to - # lock file but on the OS which supports multi I/O, records possibly be - # mixed. - # - def write(message) - if shift_log? - begin - shift_log - rescue - raise Logger::ShiftingError.new("Shifting failed. #{$!}") - end - end - - @dev.write(message) - end - - # SYNOPSIS - # Logger::LogDev#close - # - # DESCRIPTION - # Close the logging device. - # - def close - @dev.close - end - - private - - def open_logfile(filename) - if (FileTest.exist?(filename)) - open(filename, (File::WRONLY | File::APPEND)) - else - create_logfile(filename) - end - end - - def create_logfile(filename) - logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT)) - add_log_header(logdev) - logdev - end - - def add_log_header(file) - file.write( - "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName] - ) - end - - SiD = 24 * 60 * 60 - - def shift_log? - if !@shift_age or !@dev.respond_to?(:stat) - return false - end - if (@shift_age.is_a?(Integer)) - # Note: always returns false if '0'. - return (@filename && (@shift_age > 0) && (@dev.stat.size > @shift_size)) - else - now = Time.now - limit_time = case @shift_age - when /^daily$/ - eod(now - 1 * SiD) - when /^weekly$/ - eod(now - ((now.wday + 1) * SiD)) - when /^monthly$/ - eod(now - now.mday * SiD) - else - now - end - return (@dev.stat.mtime <= limit_time) - end - end - - def shift_log - # At first, close the device if opened. - if @dev - @dev.close - @dev = nil - end - if (@shift_age.is_a?(Integer)) - (@shift_age-3).downto(0) do |i| - if (FileTest.exist?("#{@filename}.#{i}")) - File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}") - end - end - File.rename("#{@filename}", "#{@filename}.0") - else - now = Time.now - postfix_time = case @shift_age - when /^daily$/ - eod(now - 1 * SiD) - when /^weekly$/ - eod(now - ((now.wday + 1) * SiD)) - when /^monthly$/ - eod(now - now.mday * SiD) - else - now - end - postfix = postfix_time.strftime("%Y%m%d") # YYYYMMDD - age_file = "#{@filename}.#{postfix}" - if (FileTest.exist?(age_file)) - raise RuntimeError.new("'#{ age_file }' already exists.") - end - File.rename("#{@filename}", age_file) - end - - @dev = create_logfile(@filename) - return true - end - - def eod(t) - Time.mktime(t.year, t.month, t.mday, 23, 59, 59) - end - end - - - # DESCRIPTION - # Application -- Add logging support to your application. - # - # USAGE - # 1. Define your application class as a sub-class of this class. - # 2. Override 'run' method in your class to do many things. - # 3. Instanciate it and invoke 'start'. - # - # EXAMPLE - # class FooApp < Application - # def initialize(foo_app, application_specific, arguments) - # super('FooApp') # Name of the application. - # end - # - # def run - # ... - # log(WARN, 'warning', 'my_method1') - # ... - # @log.error('my_method2') { 'Error!' } - # ... - # end - # end - # - # status = FooApp.new(....).start - # - class Application - include Logger::Severity - - attr_reader :appname - attr_reader :logdev - - # SYNOPSIS - # Application.new(appname = '') - # - # ARGS - # appname Name String of the application. - # - # DESCRIPTION - # Create an instance. Log device is STDERR by default. - # - def initialize(appname = nil) - @appname = appname - @log = Logger.new(STDERR) - @log.progname = @appname - @level = @log.level - end - - # SYNOPSIS - # Application#start - # - # DESCRIPTION - # Start the application. - # - # RETURN - # Status code. - # - def start - status = -1 - begin - log(INFO, "Start of #{ @appname }.") - status = run - rescue - log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n")) - ensure - log(INFO, "End of #{ @appname }. (status: #{ status.to_s })") - end - status - end - - # SYNOPSIS - # Application#set_log(log, shift_age, shift_size) - # - # ARGS - # (Args are explained in the class Logger) - # - # DESCRIPTION - # Set the log device for this application. - # - def set_log(logdev, shift_age = 0, shift_size = 102400) - @log = Logger.new(logdev, shift_age, shift_size) - @log.progname = @appname - @log.level = @level - end - - def log=(logdev) - set_log(logdev) - end - - - # SYNOPSIS - # Application#level=(severity) - # - # ARGS - # level Severity threshold. - # - # DESCRIPTION - # Set severity threshold. - # - def level=(level) - @level = level - @log.level = @level - end - - protected - - # SYNOPSIS - # Application#log(severity, comment = nil) { ... } - # - # ARGS - # severity Severity. See above to give this. - # comment Message String. - # block Can be omitted. Called to get a message String if - # comment is nil or omitted. - # - # DESCRIPTION - # Log a log if the given severity is enough severe. - # For more detail, see Log.add. - # - # RETURN - # true if succeed, false if failed. - # When the given severity is not enough severe, - # Log no message, and returns true. - # - def log(severity, message = nil, &block) - @log.add(severity, message, @appname, &block) if @log - end - - private - - def run - raise RuntimeError.new('Method run must be defined in the derived class.') - end - end -end |
