Learn R Programming

lgr (version 0.3.4)

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

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

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. (This mechanism does not work of the Logger is initialized with Logger$new())

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.

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:

name

character scalar. A hierarchical value (separated by `"/"``) that indicates the loggers name and its ancestors. If a logger is created with get_logger() uniqueness of the name is enforced.

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, file, text, list

Load a Logger configuration. cfg can be either

  • 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,

  • NULL (to reset the logger config to the default/unconfigured state)

The arguments file, text and list can 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(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 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)
# }

Run the code above in your browser using DataLab