class Logger


})
“#{datetime}: #{msg}n”
Logger.new(logdev, formatter: proc {|severity, datetime, progname, msg|
or via the constructor.
# e.g. “2005-09-22 08:51:08 +0900: hello world”
end
“#{datetime}: #{msg}n”
logger.formatter = proc do |severity, datetime, progname, msg|
Or, you may change the overall format via the #formatter= method.
Logger.new(logdev, datetime_format: ‘%Y-%m-%d %H:%M:%S’)
or via the constructor.
# e.g. “2004-01-03 00:54:26”
logger.datetime_format = ‘%Y-%m-%d %H:%M:%S’
You may change the date and time format via #datetime_format=.
I, [1999-03-03T02:34:24.895701 #19074] INFO – Main: info.
Log sample:
SeverityID, [DateTime #pid] SeverityLabel – ProgName: message
Log format:
default. The default format and a sample are shown below:
Log messages are rendered in the output stream in a certain format by
== Format
Logger.new(logdev, level: ‘INFO’)
Logger.new(logdev, level: :info)
Logger.new(logdev, level: Logger::INFO)
4. Constructor
# :debug < :info < :warn < :error < :fatal < :unknown
logger.level = ‘INFO’
logger.level = :info
3. Symbol or String (case insensitive)
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
logger.level = Logger::INFO
2. Log4r (somewhat) compatible interface.
logger.sev_threshold = Logger::WARN
1. Original interface.
=== Setting severity threshold
logger.close
=== How to close a logger
level is not set to show the debug message.
Here, the string concatenation is done every time, even if the log
logger.debug(“This is a ” + potentially + “ expensive operation”)
and the entire block will not even be evaluated. Compare to this:
If the logger’s level is INFO or higher, no debug messages will be logged,
logger.debug { “This is a ” + potentially + “ expensive operation” }
logged. For example, if we have the following:
but to delay their evaluation until and unless the message is
The block form allows you to create potentially complex log messages,
logger.add(Logger::FATAL) { ‘Fatal error!’ }
4. With severity.
logger.info(‘initialize’) { “Initializing…” }
3. With progname.
logger.error “Argument #{@foo} mismatch.”
2. Message as a string.
logger.fatal { “Argument ‘foo’ not given.” }
1. Message in a block.
dynamic) level.
debug. add is used below to log a message of an arbitrary (perhaps
messages of various levels? Other methods in this family are warn and
Notice the different methods (fatal, error, info) being used to log
=== How to log a message
logger = Logger.new(‘foo.log’, ‘monthly’)
logger = Logger.new(‘foo.log’, ‘weekly’)
logger = Logger.new(‘foo.log’, ‘daily’)
5. Create a logger which ages the logfile daily/weekly/monthly.
logger = Logger.new(‘foo.log’, 10, 1024000)
Leave 10 “old” log files where each file is about 1,024,000 bytes.
4. Create a logger which ages the logfile once it reaches a certain size.
logger = Logger.new(file)
# file = File.open(‘foo.log’, File::WRONLY | File::APPEND | File::CREAT)
# To create new logfile, add File::CREAT like:
file = File.open(‘foo.log’, File::WRONLY | File::APPEND)
3. Create a logger for the specified file.
logger = Logger.new(‘logfile.log’)
2. Create a logger for the file which has the specified name.
logger = Logger.new(STDOUT)
logger = Logger.new(STDERR)
1. Create a logger which logs messages to STDERR/STDOUT.
complexity.
The options below give you various choices, in more or less increasing
=== How to create a logger
== HOWTOs
shows you how to achieve these things.
specifying a program name in conjunction with the message. The next section
auto-rolling of log files, setting the format of log messages, and
There are several interesting features that Logger provides, like
=== Features
discarded.
fatal messages are recorded. The debug and info messages are silently
Because the Logger’s level is set to WARN, only the warning, error, and
end
logger.fatal(err)
logger.fatal(“Caught exception; exiting”)
rescue => err
end
end
logger.error(“Line in wrong format: #{line.chomp}”)
unless line =~ /^(w+) = (.*)$/
File.foreach(path) do |line|
begin
path = “a_non_existent_file”
logger.warn(“Nothing to do!”)
logger.info(“Program started”)
logger.debug(“Created logger”)
logger.level = Logger::WARN
logger = Logger.new(STDOUT)
require ‘logger’
level of WARN:
This creates a Logger that outputs to the standard output stream, with a
=== Example
logger.info(input)
}
original_formatter.call(severity, datetime, progname, msg.dump)
logger.formatter = proc { |severity, datetime, progname, msg|
original_formatter = Logger::Formatter.new
You can use #formatter= for escaping all data.
logger.info(“User-input: %p” % input)
logger.info(“User-input: #{input.dump}”)
is passed to Logger, and manually escape the untrusted data:
Developers should be aware of when potentially malicious data (user-input)
Note: Logger does not escape or sanitize any messages passed to it.
DEBUG.
want to know about the program’s internal state, and would set the Logger to
When you are developing the system, however, you probably
INFO or even WARN.
For instance, in a production system, you may have your Logger set to
DEBUG
Low-level information for developers.
INFO
Generic (useful) information about system operation.
WARN
A warning.
ERROR
A handleable error condition.
FATAL
An unhandleable error that results in a program crash.
UNKNOWN

An unknown message that should always be logged.
The levels are:
at that level or higher will be printed.
their importance. You can then give the Logger a level, and only messages
The messages have associated levels, such as INFO or ERROR that indicate
you can use to output messages.
The Logger class provides a simple but sophisticated logging utility that
== Description

def <<(msg)


device exists, return +nil+.
Dump given message to the log device without any formatting. If no log
def <<(msg)
  @logdev&.write(msg)
end

def add(severity, message = nil, progname = nil)


* If the OS supports multi I/O, records possibly may be mixed.
* Append open does not need to lock file.
* Logfile is not locked.

=== Bugs

implementation if required.
including message, class, and backtrace. See #msg2str for the
A special case is an +Exception+ object, which will be printed in detail,
if the given object is not a String.
converted to a String in order to log it. Generally, +inspect+ is used
Message format: +message+ can be any object, but it has to be

#error, and #fatal.
logging method. Users will be more inclined to use #debug, #info, #warn,
Log a message if the given severity is high enough. This is the generic

=== Description

log no message, and return +true+.
When the given severity is not high enough (for this particular logger),

=== Return

Can be omitted. Called to get a message string if +message+ is nil.
+block+::
+message+ and +block+ are given.
Program name string. Can be omitted. Treated as a message if no
+progname+::
The log message. A String or Exception.
+message+::
+WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
+severity+::

=== Args

Logger#add(severity, message = nil, progname = nil) { ... }
:call-seq:
def add(severity, message = nil, progname = nil)
  severity ||= UNKNOWN
  if @logdev.nil? or severity < level
    return true
  end
  if progname.nil?
    progname = @progname
  end
  if message.nil?
    if block_given?
      message = yield
    else
      message = progname
      progname = @progname
    end
  end
  @logdev.write(
    format_message(format_severity(severity), Time.now, progname, message))
  true
end

def close


Close the logging device.
def close
  @logdev&.close
end

def datetime_format

Returns the date format being used. See #datetime_format=
def datetime_format
  @default_formatter.datetime_format
end

def datetime_format=(datetime_format)

+datetime_format+:: A string suitable for passing to +strftime+.

Set date-time format.
def datetime_format=(datetime_format)
  @default_formatter.datetime_format = datetime_format
end

def debug(progname = nil, &block)


See #info for more information.

Log a +DEBUG+ message.
def debug(progname = nil, &block)
  add(DEBUG, nil, progname, &block)
end

def debug!; self.level = DEBUG; end

Sets the severity to DEBUG.
def debug!; self.level = DEBUG; end

def debug?; level <= DEBUG; end

+DEBUG+ messages.
Returns +true+ iff the current severity level allows for the printing of
def debug?; level <= DEBUG; end

def error(progname = nil, &block)


See #info for more information.

Log an +ERROR+ message.
def error(progname = nil, &block)
  add(ERROR, nil, progname, &block)
end

def error!; self.level = ERROR; end

Sets the severity to ERROR.
def error!; self.level = ERROR; end

def error?; level <= ERROR; end

+ERROR+ messages.
Returns +true+ iff the current severity level allows for the printing of
def error?; level <= ERROR; end

def fatal(progname = nil, &block)


See #info for more information.

Log a +FATAL+ message.
def fatal(progname = nil, &block)
  add(FATAL, nil, progname, &block)
end

def fatal!; self.level = FATAL; end

Sets the severity to FATAL.
def fatal!; self.level = FATAL; end

def fatal?; level <= FATAL; end

+FATAL+ messages.
Returns +true+ iff the current severity level allows for the printing of
def fatal?; level <= FATAL; end

def format_message(severity, datetime, progname, msg)

def format_message(severity, datetime, progname, msg)
  (@formatter || @default_formatter).call(severity, datetime, progname, msg)
end

def format_severity(severity)

def format_severity(severity)
  SEV_LABEL[severity] || 'ANY'
end

def info(progname = nil, &block)


See #add.

=== Return

program name (which you can do with #progname= as well).
You'll probably stick to the second form above, unless you want to provide a

logger.info { "User typed #{input}" }
# ...
logger.info "Waiting for input from user"
# ...
logger.info("MainApp") { "Received connection from #{ip}" }

=== Examples

are only called when the logger is configured to show them.
allows you to create potentially expensive logging messages that
the logger's level is sufficient to log the message. This
+block+:: Evaluates to the message to log. This is not evaluated unless
log message. The default can be set with #progname=.
+progname+:: In the block form, this is the #progname to use in the
+message+:: The message to log; does not need to be a String.

Log an +INFO+ message.

info(progname, &block)
info(message)
:call-seq:
def info(progname = nil, &block)
  add(INFO, nil, progname, &block)
end

def info!; self.level = INFO; end

Sets the severity to INFO.
def info!; self.level = INFO; end

def info?; level <= INFO; end

+INFO+ messages.
Returns +true+ iff the current severity level allows for the printing of
def info?; level <= INFO; end

def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,


Create an instance.

=== Description

Default is '%Y%m%d'.
The log file suffix format for +daily+, +weekly+ or +monthly+ rotation.
+shift_period_suffix+::
Use binary mode on the log device. Default value is false.
+binmode+::
Date and time format. Default value is '%Y-%m-%d %H:%M:%S'.
+datetime_format+::
Logging formatter. Default values is an instance of Logger::Formatter.
+formatter+::
Program name to include in log messages. Default value is nil.
+progname+::
Logging severity threshold. Default values is Logger::DEBUG.
+level+::
Integer). Defaults to +1048576+ (1MB).
Maximum logfile size in bytes (only applies when +shift_age+ is a positive
+shift_size+::
rotation.
+weekly+ or +monthly+). Default value is 0, which disables log file
Number of old log files to keep, *or* frequency of rotation (+daily+,
+shift_age+::
+STDOUT+, +STDERR+, or an open file).
The log device. This is a filename (String) or IO object (typically
+logdev+::

=== Args

Logger.new(logdev, datetime_format: '%Y-%m-%d %H:%M:%S')
Logger.new(logdev, formatter: formatter)
Logger.new(logdev, progname: 'progname')
Logger.new(logdev, level: :info)
Logger.new(logdev, shift_age = 'weekly')
Logger.new(logdev, shift_age = 0, shift_size = 1048576)
:call-seq:
def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
               progname: nil, formatter: nil, datetime_format: nil,
               binmode: false, shift_period_suffix: '%Y%m%d')
  self.level = level
  self.progname = progname
  @default_formatter = Formatter.new
  self.datetime_format = datetime_format
  self.formatter = formatter
  @logdev = nil
  if logdev
    @logdev = LogDevice.new(logdev, shift_age: shift_age,
      shift_size: shift_size,
      shift_period_suffix: shift_period_suffix,
      binmode: binmode)
  end
end

def level=(severity)

+severity+:: The Severity of the log message.

Set logging severity threshold.
def level=(severity)
  if severity.is_a?(Integer)
    @level = severity
  else
    case severity.to_s.downcase
    when 'debug'
      @level = DEBUG
    when 'info'
      @level = INFO
    when 'warn'
      @level = WARN
    when 'error'
      @level = ERROR
    when 'fatal'
      @level = FATAL
    when 'unknown'
      @level = UNKNOWN
    else
      raise ArgumentError, "invalid log level: #{severity}"
    end
  end
end

def reopen(logdev = nil)


Reopen a log device.

=== Description

it is +nil+, do nothing for IO. Default is +nil+.
+STDOUT+, +STDERR+, or an open file). reopen the same filename if
The log device. This is a filename (String) or IO object (typically
+logdev+::

=== Args

Logger#reopen(logdev)
Logger#reopen
:call-seq:
def reopen(logdev = nil)
  @logdev.reopen(logdev)
  self
end

def unknown(progname = nil, &block)


See #info for more information.

level is.
Log an +UNKNOWN+ message. This will be printed no matter what the logger's
def unknown(progname = nil, &block)
  add(UNKNOWN, nil, progname, &block)
end

def warn(progname = nil, &block)


See #info for more information.

Log a +WARN+ message.
def warn(progname = nil, &block)
  add(WARN, nil, progname, &block)
end

def warn!; self.level = WARN; end

Sets the severity to WARN.
def warn!; self.level = WARN; end

def warn?; level <= WARN; end

+WARN+ messages.
Returns +true+ iff the current severity level allows for the printing of
def warn?; level <= WARN; end