Creating log files with R

R wallpaper

In this short post, I explain how creating log files with R using log4r package.

Scenario

So, I want to create a custom log for debugging.

Solution

log4r is a fast, lightweight, object-oriented approach to logging in R based on the widely-emulated Apache Log4j project.

log4r differs from other R logging packages in its focus on performance and simplicity. As such, it has fewer features – although it is still quite extensible, as seen below – but is much faster. See vignette("performance", package = "log4r") for details.

Installation

The package is available from CRAN:

install.packages("log4r")

If you want to use the development version, you can install the package from GitHub as follows:

# install.packages("remotes")
remotes::install_github("johnmyleswhite/log4r")

Usage

Logging is configured by passing around logger objects created by logger(). By default, this will log to the console and suppress messages below the "INFO" level:

logger <- logger()

info(logger, "Located nearest gas station.")
#> INFO  [2019-09-04 16:31:04] Located nearest gas station.
warn(logger, "Ez-Gas sensor network is not available.")
#> WARN  [2019-09-04 16:31:04] Ez-Gas sensor network is not available.
debug(logger, "Debug messages are suppressed by default.")

Logging destinations are controlled by Appenders, a few of which are provided by the package. For instance, if we want to debug-level messages to a file:

log_file <- tempfile()
logger <- logger("DEBUG", appenders = file_appender(log_file))

info(logger, "Messages are now written to the file instead.")
debug(logger, "Debug messages are now visible.")

readLines(log_file)
#> [1] "INFO  [2019-09-04 16:31:04] Messages are now written to the file instead."
#> [2] "DEBUG [2019-09-04 16:31:04] Debug messages are now visible."

The appenders parameter takes a list, so you can log to multiple destinations transparently.

To control the format of the messages you can change the Layout used by each appender. Layouts are functions; you can write your own quite easily:

my_layout <- function(level, ...) {
  paste0(format(Sys.time()), " [", level, "] ", ..., collapse = "")
}

logger <- logger(appenders = console_appender(my_layout))
info(logger, "Messages should now look a little different.")
#> 2019-09-04 16:31:04 [INFO] Messages should now look a little different.

Real implementation

This example will give you log messages in the console output and in a text file. So, after loading the package we have four statements that setup the logging:

  • set the name of the text file that will contain the log messages
  • define the function that will write messages to the console (all default arguments)
  • define the function that will write messages to the text file (all default arguments except the name of the text file)
  • indicate that you want to use logging messages with severity INFO and higher with the functions you just defined

Then I define three functions as examples of a log call for resp. the INFO, ERROR and DEBUG level.
In your algorithm you will insert the log4r::infolog4r::error and log4r::debug calls at the points where you want them.

So, I call the three functions and at the end I show that the text file indeed contains the same messages that are shown in the console output.

library(log4r)
#> 
#> Attaching package: 'log4r'
#> The following object is masked from 'package:base':
#> 
#>     debug

my_logfile = "my_logfile.txt"

my_console_appender = console_appender(layout = default_log_layout())
my_file_appender = file_appender(my_logfile, append = TRUE, 
                            layout = default_log_layout())

my_logger <- log4r::logger(threshold = "INFO", 
                appenders= list(my_console_appender,my_file_appender))

log4r_info <- function() {
  log4r::info(my_logger, "Info_message.")
}

log4r_error <- function() {
  log4r::error(my_logger, "Error_message")
}

log4r_debug <- function() {
  log4r::debug(my_logger, "Debug_message")
}

log4r_debug() # will not trigger log entry because threshold was set to INFO

log4r_info() 
#> INFO  [2020-07-01 12:48:02] Info_message.

log4r_error() 
#> ERROR [2020-07-01 12:48:02] Error_message

readLines(my_logfile)
#> [1] "INFO  [2020-07-01 12:48:02] Info_message."
#> [2] "ERROR [2020-07-01 12:48:02] Error_message"

More about R

So, this is how you are creating log files with R. Here some more posts about it:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.