Loggers
A Logger produces a LogEvent that contains a log message along with
metadata (timestamp, calling function, ...) and dispatches it to one or
more Appenders which are responsible for the output (console, file, ...)
of the event. lgr comes with a single pre-configured Logger called the
root Logger that can be accessed via lgr$<...>. Instantiation of new
Loggers is done with get_logger(). It is advisable to instantiate a
separate Logger with a descriptive name for each package/script in which
you use lgr.
lgr::Filterable -> Logger
nameA character scalar. The unique name of each logger,
which also includes the names of its ancestors (separated by /).
thresholdinteger scalar. The threshold of the Logger, or if it
NULL the threshold it inherits from its closest ancestor with a
non-NULL threshold
propagateA TRUE or FALSE. The unique name of each logger,
which also includes the names of its ancestors (separated by /).
ancestryA named logical vector of containing the propagate value
of each Logger upper the inheritance tree. The names are the names of
the appenders. ancestry is an S3 class with a custom
format()/print() method, so if you want to use the plain logical
vector use unclass(lg$ancestry)
parenta Logger. The direct ancestor of the Logger.
last_eventThe last LogEvent produced by the current Logger
appendersa list of all Appenders of the Logger
inherited_appendersA list of all appenders that the Logger
inherits from its ancestors
exception_handlera function. See $set_exception_handler and
$handle_exception
new()
Loggers should never be instantiated directly with Logger$new() but
rather via get_logger("name"). This way new Loggers are
registered in a global namespace which ensures uniqueness and
facilitates inheritance between Loggers. If "name" does not exist, a
new Logger with that name will be created, otherwise the function returns
a Reference to the existing Logger.
name is potentially a "/" separated hierarchical value like
foo/bar/baz. Loggers further down the hierarchy are descendants of the
loggers above and (by default) inherit threshold and Appenders from
their ancestors.
Logger$new( name = "(unnamed logger)", appenders = list(), threshold = NULL, filters = list(), exception_handler = default_exception_handler, propagate = TRUE )
name, appenders, threshold, filters, exception_handler, propagateSee section Active bindings.
log()
Log an event.
Logger$log(level, msg, ..., timestamp = Sys.time(), caller = get_caller(-7))
levela character or integer scalar. See log_levels.
msgcharacter. A log message. If unnamed arguments are supplied
in ..., msg is passed on to base::sprintf() (which means "%" have
to be escaped), otherwise msg is left as-is.
...unnamed arguments in ... must be character scalars and
are passed to base::sprintf(). Named arguments must have unique names
but can be arbitrary R objects that are passed to LogEvent$new() and
will be turned into custom fields.
timestampPOSIXct. Timestamp of the event.
callera character scalar. The name of the calling function.
fatal()
Log an Event fatal priority
Logger$fatal(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
error()
Log an Event error priority
Logger$error(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
warn()
Log an Event warn priority
Logger$warn(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
info()
Log an Event info priority
Logger$info(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
debug()
Log an Event debug priority
Logger$debug(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
trace()
Log an Event trace priority
Logger$trace(msg, ..., caller = get_caller(-8L))
msg, ..., callersee $log()
list_log()
list_log() is a shortcut for do.call(Logger$log, x).
See https://github.com/s-fleck/joblog for an R package that
leverages this feature to create custom log event types for tracking
the status of cron jobs.
Logger$list_log(x)
xa named list that must at least contain the named elements
level and timestamp
lg <- get_logger("test")
lg$list_log(list(level = 400, msg = "example"))
config()
Load a Logger configuration.
Logger$config(cfg, file, text, list)
cfg a special list object with any or all of the the following elements:
appenders, threshold, filters, propagate, exception_handler,
the path to a YAML/JSON config file,
a character scalar containing YAML/JSON,
NULL (to reset the logger config to the default/unconfigured state)
file, text, listcan be used as an alternative to
cfg that enforces that the supplied argument is of the specified
type. See logger_config for details.
add_appender()
Add an Appender to the Logger
Logger$add_appender(appender, name = NULL)
appendera single Appender
namea character scalar. Optional but recommended.
lg <- get_logger("test")
lg$add_appender(AppenderConsole$new(), name = "myconsole")
lg$appenders[[1]]
lg$appenders$myconsole
lg$remove_appender("myconsole")
lg$config(NULL) # reset config
remove_appender()
remove an appender
Logger$remove_appender(pos)
posinteger index or character name of the Appender(s) to
remove
handle_exception()
To prevent errors in the logging logic from crashing the whole script,
Loggers pass errors they encounter to an exception handler. The default
behaviour is to demote errors to warnings. See also
set_exception_handler().
Logger$handle_exception(expr)
exprexpression to be evaluated.
set_exception_handler()
Set the exception handler of a logger
Logger$set_exception_handler(fun)
funa function with the single argument e (an error condition)
lgr$info(stop("this produces a warning instead of an error"))
set_propagate()
Should a Logger propagate events to the Appenders of its ancestors?
Logger$set_propagate(x)
xTRUE or FALSE. Should LogEvents be passed on to the appenders
of the ancestral Loggers?
set_threshold()
Set the minimum log level of events that a Logger should process
Logger$set_threshold(level)
levelcharacter or integer scalar. The minimum
log level that triggers this Logger
set_appenders()
Set the Logger's Appenders
Logger$set_appenders(x)
xsingle Appender or a list thereof. Appenders control the
output of a Logger. Be aware that a Logger also inherits the Appenders
of its ancestors (see vignette("lgr", package = "lgr") for more info
about Logger inheritance).
spawn()
Spawn a child Logger.
This is very similar to using get_logger(), but
can be useful in some cases where Loggers are created programmatically
Logger$spawn(name)
namecharacter vector. Name of the child logger
get_logger("foo/bar")$spawn("baz") is equivalent
to get_logger("foo/bar/baz")
If you are a package developer you should define a new Logger for each package, but you do not need to configure it. The user of the package should decide how and where to output logging, usually by configuring the root Logger (new Appenders added/removed, Layouts modified, etc...).
# lgr::lgr is the root logger that is always available
lgr$info("Today is a good day")
lgr$fatal("This is a serious error")
# Loggers use sprintf() for string formatting by default
lgr$info("Today is %s", Sys.Date() )
# If no unnamed `...` are present, msg is not passed through sprintf()
lgr$fatal("100% bad") # so this works
lgr$fatal("%s%% bad", 100) # if you use unnamed arguments, you must escape %
# You can create new loggers with get_logger()
tf <- tempfile()
lg <- get_logger("mylogger")$set_appenders(AppenderFile$new(tf))
# The new logger passes the log message on to the appenders of its parent
# logger, which is by default the root logger. This is why the following
# writes not only the file 'tf', but also to the console.
lg$fatal("blubb")
readLines(tf)
# This logger's print() method depicts this relationship.
child <- get_logger("lg/child")
print(child)
print(child$name)
# use formatting strings and custom fields
tf2 <- tempfile()
lg$add_appender(AppenderFile$new(tf2, layout = LayoutJson$new()))
lg$info("Not all %s support custom fields", "appenders", type = "test")
cat(readLines(tf), sep = "\n")
cat(readLines(tf2), sep = "\n")
# cleanup
unlink(c(tf, tf2))
lg$config(NULL) # reset logger config
# LoggerGlue
# You can also create a new logger that uses the awesome glue library for
# string formatting instead of sprintf
if (requireNamespace("glue")){
lg <- get_logger_glue("glue")
lg$fatal("blah ", "fizz is set to: {fizz}", foo = "bar", fizz = "buzz")
# prevent creation of custom fields with prefixing a dot
lg$fatal("blah ", "fizz is set to: {.fizz}", foo = "bar", .fizz = "buzz")
#' # completely reset 'glue' to an unconfigured vanilla Logger
get_logger("glue", reset = TRUE)
}
# Configuring a Logger
lg <- get_logger("test")
lg$config(NULL) # resets logger to unconfigured state
# With setters
lg$
set_threshold("error")$
set_propagate(FALSE)$
set_appenders(AppenderConsole$new(threshold = "info"))
lg$config(NULL)
# With a list
lg$config(list(
threshold = "error",
propagate = FALSE,
appenders = list(AppenderConsole$new(threshold = "info"))
))
lg$config(NULL) # resets logger to unconfigured state
# Via YAML
cfg <- "
Logger:
threshold: error
propagate: false
appenders:
AppenderConsole:
threshold: info
"
lg$config(cfg)
lg$config(NULL)
## ------------------------------------------------
## Method `Logger$list_log`
## ------------------------------------------------
lg <- get_logger("test")
lg$list_log(list(level = 400, msg = "example"))
## ------------------------------------------------
## Method `Logger$add_appender`
## ------------------------------------------------
lg <- get_logger("test")
lg$add_appender(AppenderConsole$new(), name = "myconsole")
lg$appenders[[1]]
lg$appenders$myconsole
lg$remove_appender("myconsole")
lg$config(NULL) # reset config
## ------------------------------------------------
## Method `Logger$set_exception_handler`
## ------------------------------------------------
lgr$info(stop("this produces a warning instead of an error"))Please choose more modern alternatives, such as Google Chrome or Mozilla Firefox.