The following vignette presents benchmarks for log4r against all general-purpose logging packages available on CRAN:
Each logging package features slightly different capabilities, but these benchmarks are focused on the two situations common to using all of them:
The first of these is likely the most common kind of logging done by end users, although some may chose to log to files, over HTTP, or to the system log (among others). Yet a benchmark of these other scenarios would largely show the relative expense of these operations, instead of the overhead of the logic performed by the logging packages themselves.
The second measures the performance impact of leaving logging messages in running code, even if they are below the current threshold of visibility. This is another measure of overhead for each logging package.
cat()
As a reference point, we can measure how long it takes R itself to write a simple message to the console:
The following is a typical log4r setup:
The following is a typical futile.logger setup:
The following is what I believe to be a typical logging setup:
The following is what I believe to be a typical logger setup:
requireNamespace("logger")
#> Loading required namespace: logger
#> Registered S3 method overwritten by 'logger':
#> method from
#> print.loglevel log4r
# Match the behaviour of other logging packages and write to the console.
logger::log_appender(logger::appender_stdout)
logger_info <- function() {
logger::log_info("Info message.")
}
logger_debug <- function() {
logger::log_debug("Debug message.")
}
The following is what I believe to be a typical lgr setup:
requireNamespace("lgr")
#> Loading required namespace: lgr
lgr_logger <- lgr::get_logger("perf-test")
lgr_logger$set_appenders(list(cons = lgr::AppenderConsole$new()))
lgr_logger$set_propagate(FALSE)
lgr_info <- function() {
lgr_logger$info("Info message.")
}
lgr_debug <- function() {
lgr_logger$debug("Debug message.")
}
The following is what I believe to be a typical
loggit setup. Since we only want to log to the console,
set the output file to /dev/null
. In addition,
loggit does not have a notion of thresholds, so there
is no “do nothing” operation to test.
The rlog package currently has no configuration options other than the threshold, which is controlled via an environment variable and defaults to hiding debug-level messages:
Debug messages should print nothing.
Info messages should print to the console. Small differences in output format are to be expected.
log4r_info()
#> INFO [2025-02-15 02:54:15] Info message.
cat_info()
#> INFO [2025-02-15 02:54:15] Info message.
logging_info()
#> 2025-02-15 02:54:15.873582 INFO::Info message.
fl_info()
#> INFO [2025-02-15 02:54:15] Info message.
logger_info()
#> INFO [2025-02-15 02:54:15] Info message.
lgr_info()
#> INFO [02:54:15.879] Info message.
loggit_info()
#> {"timestamp": "2025-02-15T02:54:15+0000", "log_lvl": "INFO", "log_msg": "Info message."}
rlog_info()
#> 2025-02-15 02:54:15.881994 [INFO] Info message.
The following benchmarks all loggers defined above:
info_bench <- microbenchmark::microbenchmark(
cat = cat_info(),
log4r = log4r_info(),
futile.logger = fl_info(),
logging = logging_info(),
logger = logger_info(),
lgr = lgr_info(),
loggit = loggit_info(),
rlog = rlog_info(),
times = 500,
control = list(warmups = 50)
)
debug_bench <- microbenchmark::microbenchmark(
cat = cat_debug(),
log4r = log4r_debug(),
futile.logger = fl_debug(),
logging = logging_debug(),
logger = logger_debug(),
lgr = lgr_debug(),
rlog = rlog_debug(),
times = 500,
control = list(warmups = 50)
)
print(info_bench, order = "median")
#> Unit: microseconds
#> expr min lq mean median uq max
#> log4r 25.968 36.9540 40.03603 38.4570 40.1650 843.416
#> cat 41.397 49.3875 61.32011 53.2995 55.6090 2720.411
#> rlog 80.620 97.1010 102.94900 101.9510 105.4120 802.148
#> logger 196.447 228.5020 248.45544 237.7795 242.5635 2769.183
#> logging 274.963 311.4165 337.40939 319.6820 328.0130 6397.409
#> lgr 448.477 493.4515 581.81961 506.2710 514.9320 30054.172
#> loggit 610.521 653.6055 707.23426 667.2010 685.3050 5462.803
#> futile.logger 1915.488 1983.7100 2086.20225 2011.1265 2049.8285 4905.612
#> neval
#> 500
#> 500
#> 500
#> 500
#> 500
#> 500
#> 500
#> 500
print(debug_bench, order = "median")
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> cat 1.863 2.5700 4.750894 3.7675 4.1980 659.051 500
#> log4r 2.555 3.4515 6.024676 4.5535 5.5400 751.814 500
#> rlog 6.392 7.8550 11.835056 9.8235 11.8320 900.482 500
#> lgr 12.613 14.8630 19.474534 19.4465 20.4430 749.440 500
#> logger 15.488 18.8350 24.654118 23.2635 27.2105 708.734 500
#> logging 16.210 20.1030 26.706826 27.5415 29.6750 726.067 500
#> futile.logger 558.123 574.8330 611.293130 583.3400 598.5430 3220.936 500