Create a new Logger
with a severity level threshold set to warn_level
:
var logger = new Logger(warn_level)
Messages with a severity equal or higher than warn_level
will be displayed:
logger.error "Displays an error."
logger.warn "Displays a warning."
Messages with a lower severity are silenced:
logger.info "Displays nothing."
FileLogger
can be used to output the messages into a file:
var log_file = "my.log"
logger = new FileLogger(warn_level, log_file, append = false)
logger.error("An error")
logger.info("Some info")
logger.close
assert log_file.to_path.read_all == "An error\n"
log_file.to_path.delete
Each message is associated with a level that indicate its severity.
Only messages with a severity equal to or higher than the logger level
threshold will be displayed.
Severity levels from the most severe to the least severe:
unknown_level
: An unknown message that should always be outputted.fatal_level
: An unhandleable error that results in a program crash.error_level
: A handleable error condition.warn_level
: A warning.info_level
: Generic (useful) information about system operation.debug_level
: Low-level information for developpers.You can create custom formatters by implementing the Formatter
interface.
class MyFormatter
super Formatter
redef fun format(level, message) do
if level < warn_level then return super
return "!!!{message}!!!"
end
end
See DefaultFormatter
for a more advanced implementation example.
Each Logger can be given a default formatter used to format the every messages before outputting them:
var formatter = new MyFormatter
var stderr = new StringWriter
var logger = new Logger(warn_level, stderr, formatter)
logger.warn("This is a warning.")
assert stderr.to_s.trim.split("\n").last == "!!!This is a warning.!!!"
Optionally, a Formatter
can be given to replace the default_formatter
used by default:
logger = new Logger(warn_level, stderr, null)
# Display a message without any formatter
logger.warn("This is a warning.")
assert stderr.to_s.trim.split("\n").last == "This is a warning."
# Display a message with a custom formatter
logger.warn("This is a warning.", formatter)
assert stderr.to_s.trim.split("\n").last == "!!!This is a warning.!!!"
core :: union_find
union–find algorithm using an efficient disjoint-set data structure
# A simple logger for Nit
#
# ## Basic Usage
#
# Create a new `Logger` with a severity level threshold set to `warn_level`:
#
# ~~~
# var logger = new Logger(warn_level)
# ~~~
#
# Messages with a severity equal or higher than `warn_level` will be displayed:
#
# ~~~
# logger.error "Displays an error."
# logger.warn "Displays a warning."
# ~~~
#
# Messages with a lower severity are silenced:
#
# ~~~
# logger.info "Displays nothing."
# ~~~
#
# `FileLogger` can be used to output the messages into a file:
#
# ~~~
# var log_file = "my.log"
#
# logger = new FileLogger(warn_level, log_file, append = false)
# logger.error("An error")
# logger.info("Some info")
# logger.close
#
# assert log_file.to_path.read_all == "An error\n"
# log_file.to_path.delete
# ~~~
#
# ## Severity levels
#
# Each message is associated with a level that indicate its severity.
# Only messages with a severity equal to or higher than the logger `level`
# threshold will be displayed.
#
# Severity levels from the most severe to the least severe:
#
# * `unknown_level`: An unknown message that should always be outputted.
# * `fatal_level`: An unhandleable error that results in a program crash.
# * `error_level`: A handleable error condition.
# * `warn_level`: A warning.
# * `info_level`: Generic (useful) information about system operation.
# * `debug_level`: Low-level information for developpers.
#
# ## Formatting messages
#
# You can create custom formatters by implementing the `Formatter` interface.
#
# ~~~
# class MyFormatter
# super Formatter
#
# redef fun format(level, message) do
# if level < warn_level then return super
# return "!!!{message}!!!"
# end
# end
# ~~~
#
# See `DefaultFormatter` for a more advanced implementation example.
#
# Each Logger can be given a default formatter used to format the every messages
# before outputting them:
#
# ~~~
# var formatter = new MyFormatter
# var stderr = new StringWriter
# var logger = new Logger(warn_level, stderr, formatter)
#
# logger.warn("This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "!!!This is a warning.!!!"
# ~~~
#
# Optionally, a `Formatter` can be given to replace the `default_formatter`
# used by default:
#
# ~~~
# # Create a formatter with no default decorator
# logger = new Logger(warn_level, stderr, null)
#
# # Display a message without any formatter
# logger.warn("This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
#
# # Display a message with a custom formatter
# logger.warn("This is a warning.", formatter)
# assert stderr.to_s.trim.split("\n").last == "!!!This is a warning.!!!"
# ~~~
module logger
import console
# A simple logging utility
#
# `Logger` provides a simple way to output messages from applications.
#
# Each message is associated with a level that indicate its severity.
# Only messages with a severity equal to or higher than the logger `level`
# threshold will be displayed.
#
# ~~~
# var logger = new Logger(warn_level)
# assert logger.unknown("unkown")
# assert logger.fatal("fatal")
# assert logger.error("error")
# assert logger.warn("warn")
# assert not logger.info("info")
# assert not logger.debug("debug")
# ~~~
class Logger
# Severity threshold
#
# Messages with a severity level greater than or equal to `level` will be displayed.
# Default is `warn_level`.
#
# See `unknown_level`, `fatal_level`, error_level``, `warn_level`,
# `info_level` and `debug_level`.
var level: Int = warn_level is optional, writable
# Kind of `Writer` used to output messages
type OUT: Writer
# Writer used to output messages
#
# Default is `stderr`.
var out: OUT = stderr is optional
# Formatter used to format messages before outputting them
#
# By default no formatter is used.
#
# See `DefaultFormatter`.
var default_formatter: nullable Formatter = null is optional, writable
# Output a message with `level` severity
#
# Only output messages with `level` severity greater than of equal to `self.level`.
#
# ~~~
# var stderr = new StringWriter
# var logger = new Logger(warn_level, stderr, null)
#
# # This message will be displayed:
# assert logger.warn("This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
#
# # This message will not:
# assert not logger.info("This is some info.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
# ~~~
#
# Each logger can be given a default formatter used to format the messages
# before outputting them:
#
# ~~~
# var formatter = new DefaultFormatter(no_color = true)
# logger = new Logger(warn_level, stderr, formatter)
# logger.warn("This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "Warning: This is a warning."
# ~~~
#
# Optionally, a `Formatter` can be given to replace the `default_formatter`
# used by default.
#
# ~~~
# # Create a formatter with no default decorator
# logger = new Logger(warn_level, stderr, null)
#
# # Display a message without any formatter
# logger.warn("This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
#
# # Display a message with a custom formatter
# logger.warn("This is a warning.", formatter)
# assert stderr.to_s.trim.split("\n").last == "Warning: This is a warning."
# ~~~
fun add(level: Int, message: Writable, formatter: nullable Formatter): Bool do
var format = formatter or else default_formatter
if format == null then
return add_raw(level, message)
end
return add_raw(level, format.format(level, message))
end
# Output a message with `level` severity without formatting it
#
# Only output messages with `level` severity greater than of equal to `self.level`.
#
# ~~~
# var stderr = new StringWriter
# var logger = new Logger(warn_level, stderr, null)
#
# # This message will be displayed:
# assert logger.add_raw(warn_level, "This is a warning.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
#
# # This message will not:
# assert not logger.add_raw(info_level, "This is some info.")
# assert stderr.to_s.trim.split("\n").last == "This is a warning."
# ~~~
fun add_raw(level: Int, message: Writable): Bool do
if level < self.level then return false
out.write(message.write_to_string)
out.write("\n")
return true
end
# Output a message with `unknown_level` severity
#
# Unkown severity messages are always outputted.
fun unknown(message: String, formatter: nullable Formatter): Bool do
return add(unknown_level, message, formatter)
end
# Output a message with `fatal_level` severity
fun fatal(message: String, formatter: nullable Formatter): Bool do
return add(fatal_level, message, formatter)
end
# Output a message with `error_level` severity
fun error(message: String, formatter: nullable Formatter): Bool do
return add(error_level, message, formatter)
end
# Output a message with `warn_level` severity
fun warn(message: String, formatter: nullable Formatter): Bool do
return add(warn_level, message, formatter)
end
# Output a message with `info_level` severity
fun info(message: String, formatter: nullable Formatter): Bool do
return add(info_level, message, formatter)
end
# Output a message with `debug` severity
fun debug(message: String, formatter: nullable Formatter): Bool do
return add(debug_level, message, formatter)
end
end
# Log messages to a file
#
# ~~~
# var log_file = "my_file.log"
# var logger = new FileLogger(warn_level, log_file, append = false)
# logger.error("An error")
# logger.info("Some info")
# logger.close
# assert log_file.to_path.read_all == "An error\n"
#
# logger = new FileLogger(warn_level, log_file, append = true)
# logger.error("Another error")
# logger.close
# assert log_file.to_path.read_all == "An error\nAnother error\n"
#
# log_file.to_path.delete
# ~~~
class FileLogger
super Logger
autoinit level, file, append, default_formatter
redef type OUT: FileWriter
# File where messages will be written
var file: String
# Append messages to `file`
#
# If `append` is `false`, the `file` will be overwritten.
var append: Bool = true is optional
init do
var old = null
if append then
old = file.to_path.read_all
end
out = new FileWriter.open(file)
out.set_buffering_mode(0, buffer_mode_line)
if old != null then
out.write(old)
end
end
# Close the logger and its `file`
fun close do out.close
end
# Format messages before outputing them
#
# A `Logger` can use a `Formatter` to format the messages before outputting them.
#
# See `DefaultFormatter`.
interface Formatter
# Format `message` depending of its severity `level`
fun format(level: Int, message: Writable): Writable do return message
end
# Default `Logger` formatter
#
# The default formatter decorates the messages with severity labels and colors.
class DefaultFormatter
super Formatter
# Do not decorate messages with colors
#
# ~~~
# var formatter = new DefaultFormatter(no_color = true)
# assert formatter.format(error_level, "My message.") == "Error: My message."
# ~~~
var no_color = false is optional, writable
redef fun format(level, message) do
var string = message.write_to_string
if level == fatal_level then
string = "Fatal: {string}"
else if level == error_level then
string = "Error: {string}"
else if level == warn_level then
string = "Warning: {string}"
else if level == info_level then
string = "Info: {string}"
else if level == debug_level then
string = "Debug: {string}"
end
if no_color then return string
if level == fatal_level then
return string.red
else if level == error_level then
return string.red
else if level == warn_level then
return string.yellow
else if level == info_level then
return string.purple
else if level == debug_level then
return string.blue
end
return string
end
end
redef class Sys
# Unknown severity level
#
# These messages are always displayed.
#
# See `Logger`.
var unknown_level = 5
# Fatal severity level
#
# See `Logger`.
var fatal_level = 4
# Error severity level
#
# See `Logger`.
var error_level = 3
# Warning severity level
#
# See `Logger`.
var warn_level = 2
# Info severity level
#
# See `Logger`.
var info_level = 1
# Debug severity level
#
# See `Logger`.
var debug_level = 0
end
lib/logger/logger.nit:15,1--402,3