Learn R Programming

lgr (version 0.2.0)

Logger: Loggers

Description

A Logger produces a LogEvent that contains the log message along with metadata (timestamp, calling function) and dispatches it to one or several 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 only necessary if you want to take advantage of hierarchical logging as outlined in vignette("lgr", package = "lgr").

Arguments

Usage

# Cannonical way to initialize a new Logger (see "Creating Loggers")
lg <- get_logger("logger")

# R6 constructor (not recommended for productive use)
lg <- Logger$new(name = "(unnamed logger)", appenders = list(), threshold =
  NULL, filters = list(), exception_handler = default_exception_handler,
  propagate = TRUE)

lg$log(level, msg, ..., timestamp = Sys.time(), caller = get_caller(-7)) lg$fatal(msg, ..., caller = get_caller(-8L)) lg$error(msg, ..., caller = get_caller(-8L)) lg$warn(msg, ..., caller = get_caller(-8L)) lg$info(msg, ..., caller = get_caller(-8L)) lg$debug(msg, ..., caller = get_caller(-8L)) lg$trace(msg, ..., caller = get_caller(-8L)) lg$config(cfg = NULL, file = NULL, text = NULL) lg$add_appender(appender, name = NULL) lg$remove_appender(pos) lg$handle_exception(...) lg$set_name(x) lg$set_exception_handler(fun) lg$set_propagate(x) lg$set_threshold(level) lg$set_appenders(x) lg$spawn(name, ...) lg$filter(event) lg$add_filter(filter, name = NULL) lg$remove_filter(pos) lg$set_filters(filters)

lg$ancestry lg$appenders lg$exception_handler lg$inherited_appenders lg$last_event lg$name lg$parent lg$propagate lg$threshold lg$filters

Creating Loggers

If you are a package developer you should define a new Logger for each package, but you do not need to configure it. Usually only the root logger needs to be configured (new Appenders added/removed, Layouts modified, etc...).

Loggers should never be instantiated directly with Logger$new() but rather via get_logger("name"). If "name" does not exist, a new Logger with that name will be created, otherwise the function returns a Reference to the existing Logger.

The name is potentially a / separated hierarchical value like foo/bar/baz. Loggers further down the hierarchy are children of the loggers above.

All calls to get_logger() with the same name return the same Logger instance. This means that Logger instances never need to be passed between different parts of an application.

If you just want to log to an additional output (like a log file), you want a new Appender, not a new Logger.

Fields

You can modify the fields of an existing Logger with logger$set_<fieldname>(value) (see examples). Another way to configure loggers is via its $config() method.

name, set_name(x)

character scalar. A name for the Logger that should be unique among Loggers. This logger name is used in the Loggers print method and can be used by Appenders to indicate which logger the log message came from. If you define a Logger for an R Package (the most common case for defining new Loggers), the logger name should be the same name as the Package name. If you do not define a Logger name manually, a warning will be thrown.

appenders, set_appenders(x)

A single 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 structures).

threshold, set_threshold(level)

character or integer scalar. The minimum log level that triggers this Logger

exception_handler, set_exception_handler()

a function that takes a single argument e. The function used to handle errors that occur during logging. Defaults to demoting errors to warnings.

propagate, set_propagate()

TRUE or FALSE. Should LogEvents be passed on to the appenders of the ancestral Loggers?

filters, set_filters(filters)

a list that may contain functions or any R object with a filter() method. These functions must have exactly one argument: event which will get passed the LogEvent when the Filterable's filter() method is invoked. If all of these functions evaluate to TRUE the LogEvent is passed on. Since LogEvents have reference semantics, filters can also be abused to modify them before they are passed on. Look at the source code of with_log_level() or with_log_value() for examples.

Read-Only Bindings

In addition to the active bindings used to access the fields described above, Loggers also have the following additional read-only bindings:

ancestry

A 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)

inherited_appenders

A list of all inherited appenders from ancestral Loggers of the current Logger

last_event

The last LogEvent produced by the current Logger

Methods

fatal(msg, ..., caller = get_caller(-8L))

Logs a message with level fatal on this logger. If there are unnamed arguments in ..., they will be passed to base::sprintf() along with message. Named arguments will be passed as custom fields to LogEvent. If there are named arguments the names must be unique. caller refers to the name of the calling function and if specified manually must be a character scalar.

error(msg, ..., caller = get_caller(-8L))

Logs a message with level error on this logger. The arguments are interpreted as for fatal().

warn(msg, ..., caller = get_caller(-8L))

Logs a message with level warn on this logger. The arguments are interpreted as for fatal().

info(msg, ..., caller = get_caller(-8L))

Logs a message with level info on this logger. The arguments are interpreted as for fatal().

debug(msg, ..., caller = get_caller(-8L))

Logs a message with level debug on this logger. The arguments are interpreted as for fatal().

trace(msg, ..., caller = get_caller(-8L))

Logs a message with level trace on this logger. The arguments are interpreted as for fatal().

log(level, msg, ..., timestamp, caller)

If the level passes the Logger threshold a new LogEvent with level, msg, timestamp and caller is created. Unnamed arguments in ... will be combined with msg via base::sprintf(). Named arguments in ... will be passed on to LogEvent$new() as custom fields. If no unnamed arguments are present, msg will not be passed to sprintf(), so in that case you do not have to escape "%" characters. If the new LogEvent passes this Loggers filters, it will be dispatched to the relevant Appenders and checked against their thresholds and filters.

config(cfg = NULL, file = NULL, text = NULL

Load a Logger configuration. cfg can be either a special list object, the path to a YAML config file, or a character scalar containing YAML. The arguments file and text can used alternatively and enforce that the supplied argument is of the specified type. See logger_config for details.

add_appender(appender, name = NULL), remove_appender(pos)

Add or remove an Appender. Supplying a name is optional but recommended. After adding an Appender with logger$add_appender(AppenderConsole$new(), name = "console") you can refer to it via logger$appenders$console. remove_appender() can remove an Appender by position or name.

spawn(...)

Spawn a child Logger. get_logger("foo/bar")$spawn("baz") is equivalent to get_logger("foo/bar/baz"), but can be convenient for programmatic use when the name of the parent Logger is not known.

filter(event)

Determine whether the LogEvent x should be passed on to Appenders (TRUE) or not (FALSE). See also the active binding filters

add_filter(filter, name = NULL), remove_filter(pos)

Add or remove a filter. When adding a filter an optional name can be specified. remove_filter() can remove by position or name (if one was specified)

LoggerGlue

LoggerGlue uses glue::glue() instead of base::sprintf() to construct log messages. glue is a very well designed package for string interpolation. It makes composing log messages more flexible and comfortable at the price of an additional dependency and slightly less performance than sprintf().

glue() lets you define temporary named variables inside the call. As with the normal Logger, these named arguments get turned into custom fields; however, you can suppress this behaviour by making named argument start with a ".". Please refer to vignette("lgr", package = "lgr") for examples.

See Also

glue

Examples

Run this code
# NOT RUN {
# lgr::lgr is the root logger that is always available
lgr$info("Today is %s", Sys.Date() )
lgr$fatal("This is a serious error")

# You can create new loggers with Logger$new(). The following creates a
# logger that logs to a temporary file.
tf <- tempfile()
lg <- Logger$new("mylogger", 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
lg2 <- Logger$new("lg/child")
print(lg2)
print(lg2$ancestry)
print(lg2$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")

# The following works because if no unnamed `...` are present, msg is not
# passed through sprintf() (otherwise you would have to escape the "%")
lg$fatal("100%")

# LoggerGlue
lg <- LoggerGlue$new("glue")
lg$fatal("blah ", "fizz is set to: {fizz}", foo = "bar", fizz = "buzz")
# }

Run the code above in your browser using DataLab