class Logger


.
see details and suggestions at
shift_period_suffix;
You can set a different format using create-time option
which produces a suffix similar to the one above.
The default format for the suffix is '%Y%m%d',
- Nothing is removed.
- A new log file t.log is opened.
with a date-based suffix such as t.log.20220509.
- The base log file, t.log is closed and renamed
When the given period expires:
logger = Logger.new(‘t.log’, ‘daily’)
Example:
logger = Logger.new(‘t.log’, ‘monthly’) # Rotate log files monthly.
logger = Logger.new(‘t.log’, ‘weekly’) # Rotate log files weekly.
logger = Logger.new(‘t.log’, ‘daily’) # Rotate log files daily.
Examples:
- Argument shift_age as a string period indicator.
- Argument logdev as a file path.
For periodic rotation, call Logger.new with:
=== Periodic Rotation
- A new file t.log is opened.
- t.log is closed and renamed to t.log.0.
- +t.log.0 is renamed as t.log.1.
- t.log.1 is removed.
the log files are rotated:
Each subsequent time that t.log is full,
- A new file t.log is opened.
- t.log is closed and renamed to t.log.0.
- +t.log.0 is renamed as t.log.1.
The second time t.log is full:
- A new file t.log is opened.
- t.log is closed and renamed to t.log.0.
The first time t.log is full:
when a new entry would cause its size to exceed shift_size.
the log file is “full” and ready for rotation
Logging begins in the new log file, t.log;
logger = Logger.new(‘t.log’, 3)
For these examples, suppose:
logger = Logger.new(‘t.log’, 5, 10485760) # Five 10-megabyte files.
logger = Logger.new(‘t.log’, 3) # Three 1-megabyte files.
Examples:
defaults to 1048576 (1 megabyte).
the maximum size (in bytes) of each log file;
- Argument shift_size as a positive integer:
the number of log files to be in the rotation.
- Argument shift_age with a positive integer:
- Argument logdev as a file path.
For size-based log file rotation, call Logger.new with:
=== Size-Based Rotation
the others are closed and inactive.
- Only the most recent log file is open and active;
time interval.
- Each log file has entries for a non-overlapping
you can use log file rotation, which uses multiple log files:
To keep log files to a manageable size,
(until explicitly closed); there is no file rotation.
By default, a log file is a single file that grows indefinitely
== Log File Rotation
logger.fatal? # => true
logger.error? # => true
logger.warn? # => false
logger.info? # => false
logger.debug? # => false
logger.level = Logger::ERROR
level is to be written:
These methods return whether a given
logger.level # => 3
logger.level = Logger::ERROR
You can retrieve the log level with method #level.
logger.fatal! # => 4
logger.error! # => 3
logger.warn! # => 2
logger.info! # => 1
logger.debug! # => 0
These shorthand methods also set the level:
logger.level = Logger::ERROR
with method #level=:
You can set the log level for an existing logger
logger.add(2) # Silent.
# => E, [2022-05-11T15:17:20.933362 #20536] ERROR – : nil
logger.add(3)
logger = Logger.new($stdout, level: Logger::ERROR)
are written, while those with lower severities are not written:
With this level, entries with severity Logger::ERROR and higher
logger.level # => 3
logger = Logger.new($stdout, level: :error)
logger = Logger.new($stdout, level: ‘error’)
logger = Logger.new($stdout, level: Logger::ERROR)
using keyword argument level with an appropriate value:
You can specify a different setting in a new logger
# => D, [2022-05-11T15:10:59.773668 #20536] DEBUG – : My message
logger.add(0, “My message”)
logger.level # => 0
logger = Logger.new($stdout)
which means that all entries are to be written, regardless of severity:
The default initial level setting is Logger::DEBUG, the lowest level,
# => A, [2022-05-07T18:07:54.657491 #20536] ANY – : Most severe
logger.add(Logger::UNKNOWN, ‘Most severe’)
# => F, [2022-05-07T18:05:24.703931 #20536] FATAL – : Fatal error
logger.add(Logger::FATAL, ‘Fatal error’)
# => E, [2022-05-07T18:02:41.592912 #20536] ERROR – : Non-fatal error
logger.add(Logger::ERROR, ‘Non-fatal error’)
# => W, [2022-05-07T18:00:45.337538 #20536] WARN – : Non-error warning
logger.add(Logger::WARN, ‘Non-error warning’)
# => I, [2022-05-07T17:59:14.349167 #20536] INFO – : Non-error information
logger.add(Logger::INFO, ‘Non-error information’)
# => D, [2022-05-07T17:57:41.776220 #20536] DEBUG – : Maximal debugging info
logger.add(Logger::DEBUG, ‘Maximal debugging info’)
logger = Logger.new($stdout)
These are the defined severities (least severe to most severe):
written to the log, based on the entry’s severity.
The log level setting determines whether an entry is actually
== Log Level
logger.progname # => “mung”
:
The current program name may be retrieved with method
logger.progname = ‘mung’
by a call to method #progname=:
The default program name for an existing logger may be set
logger = Logger.new(‘t.log’, progname: ‘mung’)
Logger.new via optional keyword argument progname:
The default program name for a new logger may be set in the call to
# => I, [2022-05-07T18:17:38.084716 #20536] INFO – mung: My message
logger.add(Logger::INFO, ‘My message’, ‘mung’)
logger = Logger.new($stdout)
The program name is an optional argument to an entry method:
=== Program Name
see the example at formatter=.
You can use a custom formatter to escape message data;
may be in the message, and should explicitly escape untrusted data.
Developers should be aware that malicious data (user input)
the message passed to it.
Note: Logger::Formatter does not escape or sanitize
- Anything else: message.inspect is used.
- An Exception: message.message is used.
- A string: used as-is.
the message object may be:
For the default entry formatter, Logger::Formatter,
# => I, [2022-05-07T18:15:37.647581 #20536] INFO – : My message
logger.add(Logger::INFO, ‘My message’)
logger = Logger.new($stdout)
The message is an optional argument to an entry method:
=== Message
You can set a different format using method #datetime_format=.
# => I, [2022-05-07T17:04:32.318331 #20536] INFO – : nil
logger.add(Logger::INFO)
logger = Logger.new($stdout)
Example:
‘%Y-%m-%dT%H:%M:%S.%6N’
using this format string:
The logged timestamp is formatted by method
when the entry is created.
The timestamp for a log entry is generated automatically
=== Timestamp
the relative importance of the entry.
- Indicates to any log reader (whether a person or a program)
see Log Level.
- Determines whether the entry is selected for inclusion in the log;
The severity of a log entry has two effects:
=== Severity
logger.error(“#{my_slow_message_generator}”)
always evaluated, regardless of the log level:
Contrast this with the string form, where the string is
logger.error { my_slow_message_generator }
permits the entry actually to be written:
- Performance: the block is not evaluated unless the log level
and create a context-dependent message.
- Context: the block can evaluate the entire program context
Doing so can have two benefits:
(affects only the one entry).
- Calling any of the methods above with a block
see formatter=.
- Setting a custom format proc (affects following entries);
You can use a different entry format by:
- Message.
- Program name.
- Severity (word).
- Process id.
- Timestamp.
- Severity (one letter).
where the values to be formatted are:
“%s, [%s #%d] %5s – %s: %sn”
The default format for an entry is:
# => I, [2022-05-07T17:21:46.536234 #20536] INFO – mung: My message.
logger.add(Logger::INFO, ‘My message.’, ‘mung’)
logger = Logger.new($stdout)
Example:
- A program name.
- A message.
And may also have:
- An automatically created timestamp.
- A severity (the required argument to #add).
An entry always has:
see {Log Level}[rdoc-ref:Logger@Log+Level]
depending on the entry’s severity and on the log level;
the entry may or may not be written to the log,
When you call any of these methods,
logger.unknown(‘Most severe’)
logger.fatal(‘Fatal error’)
logger.error(‘Non-fatal error’)
logger.warn(‘Non-error warning’)
logger.info(‘Non-error information’)
logger.debug(‘Maximal debugging info’)
These shorthand methods also add entries:
logger.add(Logger::UNKNOWN, ‘Most severe’)
logger.add(Logger::FATAL, ‘Fatal error’)
logger.add(Logger::ERROR, ‘Non-fatal error’)
logger.add(Logger::WARN, ‘Non-error warning’)
logger.add(Logger::INFO, ‘Non-error information’)
logger.add(Logger::DEBUG, ‘Maximal debugging info’)
You can add entries with method Logger#add:
== Entries
logger.close
Close the log with Logger#close:
logger.add(Logger::UNKNOWN, ‘Most severe’)
logger.add(Logger::FATAL, ‘Fatal error’)
logger.add(Logger::ERROR, ‘Non-fatal error’)
logger.add(Logger::WARN, ‘Non-error warning’)
logger.add(Logger::INFO, ‘Non-error information’)
logger.add(Logger::DEBUG, ‘Maximal debugging info’)
Add entries (level, message) with Logger#add:
logger = Logger.new($stdout)
# Log to an IO stream.
logger = Logger.new(‘t.log’, ‘daily’)
# Period-based rotated logging: daily (also allowed: ‘weekly’, ‘monthly’).
logger = Logger.new(‘t.log’, 3, 10485760)
# Size-based rotated logging: 3 10-megabyte files.
logger = Logger.new(‘t.log’)
# Single log file.
Create a log with Logger.new:
== Synopsis
require ‘logger’
All examples on this page assume that Logger has been required:
== About the Examples
that provides a record of the program’s activities.
Each such log contains a chronological sequence of entries
for your program.
you can use to create one or more
Class Logger provides a simple but sophisticated logging utility that

def <<(msg)


My message.

Output:

logger << 'My message.' # => 10
logger = Logger.new($stdout)

or +nil+ if no log device exists:
returns the number of characters written,
Writes the given +msg+ to the log with no formatting;
def <<(msg)
  @logdev&.write(msg)
end

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


- #unknown.
- #fatal.
- #error.
- #warn.
- #info.
- #debug.

These convenience methods have implicit severity:

E, [2022-05-12T16:26:35.841134 #36328] ERROR -- gnum: No good
E, [2022-05-12T16:25:55.349414 #36328] ERROR -- mung: No good
I, [2022-05-12T16:25:31.469726 #36328] INFO -- mung: mung

Output:

logger.add(Logger::ERROR, 'No good', 'gnum')
logger.add(Logger::ERROR, 'No good')
logger.add(Logger::INFO)
logger = Logger.new($stdout, progname: 'mung')

Examples:

and {Entries}[rdoc-ref:Logger@Entries] for details.
See {Log Level}[rdoc-ref:Logger@Log+Level]
depending on the entry's severity and on the log level.
Creates a log entry, which may or may not be written to the log,
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

Related: Logger#reopen.

logger.info('foo') # Prints "log writing failed. closed stream"
logger.close # => nil
logger = Logger.new('t.log')

Closes the logger; returns +nil+:
def close
  @logdev&.close
end

def datetime_format


Returns the date-time format; see #datetime_format=.
def datetime_format
  @default_formatter.datetime_format
end

def datetime_format=(datetime_format)


- +nil+: the logger uses '%Y-%m-%dT%H:%M:%S.%6N'.
{Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime].
- A string suitable for use as a format for method

Argument +datetime_format+ should be either of these:

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

def debug(progname = nil, &block)


Equivalent to calling #add with severity Logger::DEBUG.
def debug(progname = nil, &block)
  add(DEBUG, nil, progname, &block)
end

def debug!; self.level = DEBUG; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level to Logger::DEBUG.
def debug!; self.level = DEBUG; end

def debug?; level <= DEBUG; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Logger::DEBUG to be written, +false+ otherwise.
Returns +true+ if the log level allows entries with severity
def debug?; level <= DEBUG; end

def error(progname = nil, &block)


Equivalent to calling #add with severity Logger::ERROR.
def error(progname = nil, &block)
  add(ERROR, nil, progname, &block)
end

def error!; self.level = ERROR; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level to Logger::ERROR.
def error!; self.level = ERROR; end

def error?; level <= ERROR; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Logger::ERROR to be written, +false+ otherwise.
Returns +true+ if the log level allows entries with severity
def error?; level <= ERROR; end

def fatal(progname = nil, &block)


Equivalent to calling #add with severity Logger::FATAL.
def fatal(progname = nil, &block)
  add(FATAL, nil, progname, &block)
end

def fatal!; self.level = FATAL; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level to Logger::FATAL.
def fatal!; self.level = FATAL; end

def fatal?; level <= FATAL; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Logger::FATAL to be written, +false+ otherwise.
Returns +true+ if the log level allows entries with severity
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)


Equivalent to calling #add with severity Logger::INFO.
def info(progname = nil, &block)
  add(INFO, nil, progname, &block)
end

def info!; self.level = INFO; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level to Logger::INFO.
def info!; self.level = INFO; end

def info?; level <= INFO; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Logger::INFO to be written, +false+ otherwise.
Returns +true+ if the log level allows entries with severity
def info?; level <= INFO; end

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


The default is to swallow all exceptions raised.
be reraised if there is an error when writing to the log device.
- +reraise_write_errors+: An array of exception classes, which will
See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
for periodic log file rotation; default is '%Y%m%d'.
- +shift_period_suffix+: sets the format for the filename suffix
default is +false+.
- +binmode+: sets whether the logger writes in binary mode;
See #datetime_format=.
default is +nil+.
- +datetime_format+: sets the format for entry timestamp;
See {formatter=}[Logger.html#attribute-i-formatter].
- +formatter+: sets the entry formatter; default is +nil+.

Logger.new('t.log', progname: 'mung')

See {Program Name}[rdoc-ref:Logger@Program+Name]:
- +progname+: sets the default program name; default is +nil+.

Logger.new('t.log', level: Logger::ERROR)

See {Log Level}[rdoc-ref:Logger@Log+Level]:
- +level+: sets the log level; default value is Logger::DEBUG.

The keyword options are:

Logger.new($stdout)
Logger.new('t.log')

Examples:

- +nil+ or +File::NULL+: no entries are to be written.
entries are to be written to the given stream.
- An IO stream (typically +$stdout+, +$stderr+. or an open file):
new entries are appended.
to the file at that path; if the file at that path exists,
- A string filepath: entries are to be written

Argument +logdev+ must be one of:

Logger.new('t.log') # => #

returns a new logger with all default options:
With the single argument +logdev+,

Logger.new(logdev, shift_age = 0, shift_size = 1048576, **options)
: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',
               reraise_write_errors: [])
  self.level = level
  self.progname = progname
  @default_formatter = Formatter.new
  self.datetime_format = datetime_format
  self.formatter = formatter
  @logdev = nil
  @level_override = {}
  if logdev && logdev != File::NULL
    @logdev = LogDevice.new(logdev, shift_age: shift_age,
      shift_size: shift_size,
      shift_period_suffix: shift_period_suffix,
      binmode: binmode,
      reraise_write_errors: reraise_write_errors)
  end
end

def level

Logging severity threshold (e.g. Logger::INFO).
def level
  level_override[level_key] || @level
end

def level=(severity)


Logger#sev_threshold= is an alias for Logger#level=.

logger.level = :error # => :error
logger.level = 'error' # => "error"
logger.level = 3 # => 3
logger.level = Logger::ERROR # => 3

Argument +severity+ may be an integer, a string, or a symbol:

See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level; returns +severity+.
def level=(severity)
  @level = Severity.coerce(severity)
end

def level_key

def level_key
  Fiber.current
end

def level_override

Guarantee the existence of this ivar even when subclasses don't call the superclass constructor.
def level_override
  @level_override ||= {}
end

def reopen(logdev = nil)


# "E, [2022-05-12T14:23:05.847241 #22428] ERROR -- : three\n"]
# "E, [2022-05-12T14:21:27.596726 #22428] ERROR -- : one\n",
# ["# Logfile created on 2022-05-12 14:21:19 -0500 by logger.rb/v1.5.0\n",
# =>
File.readlines('t.log')
logger.close
logger.add(Logger::ERROR, 'three')
logger.reopen
logger.add(Logger::ERROR, 'two') # Prints 'log writing failed. closed stream'
logger.close
logger.add(Logger::ERROR, 'one')
logger = Logger.new('t.log')

Example:

opens the stream for append.
(usually $stdout, $stderr, or an open File object),
- If +logdev+ is an IO stream
- If +logdev+ is a filepath, opens the indicated file for append.
- If +logdev+ is +nil+, reopens the current output stream.

Sets the logger's output stream:
def reopen(logdev = nil)
  @logdev&.reopen(logdev)
  self
end

def unknown(progname = nil, &block)


Equivalent to calling #add with severity Logger::UNKNOWN.
def unknown(progname = nil, &block)
  add(UNKNOWN, nil, progname, &block)
end

def warn(progname = nil, &block)


Equivalent to calling #add with severity Logger::WARN.
def warn(progname = nil, &block)
  add(WARN, nil, progname, &block)
end

def warn!; self.level = WARN; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Sets the log level to Logger::WARN.
def warn!; self.level = WARN; end

def warn?; level <= WARN; end


See {Log Level}[rdoc-ref:Logger@Log+Level].
Logger::WARN to be written, +false+ otherwise.
Returns +true+ if the log level allows entries with severity
def warn?; level <= WARN; end

def with_level(severity)

end
logger.debug { "Hello" }
logger.with_level(:debug) do

Adjust the log level during the block execution for the current Fiber only
def with_level(severity)
  prev, level_override[level_key] = level, Severity.coerce(severity)
  begin
    yield
  ensure
    if prev
      level_override[level_key] = prev
    else
      level_override.delete(level_key)
    end
  end
end