tryCatchLog icon indicating copy to clipboard operation
tryCatchLog copied to clipboard

Add convenience functions to activate other major logging packages

Open aryoda opened this issue 6 years ago • 5 comments

#10 introduced the possibility to inject your own logging functions.

There are many logging packages at CRAN now.

It would be very convenient if tryCatchLog provides functions to activate one of these logging packages with a simple function call.

List of known logging frameworks for R (updated in-place):

  • plogr allows logging within C++ code into R' standard error stream (via the REprintf() function. This logging framework seems not to be meant for R code itself!.
  • futile.logger: logging to files, console
  • logging: Powerful R port of the popular Python logging package. Logging to console, file, sentry server etc.
  • logger (by daroczik): A lightweight, modern and flexibly logging utility for R -- heavily inspired by the futile.logger R package and logging Python module. Under active development (put on watch list ;-). Lists many other logging frameworks.
  • debugme ("zero"-overhead logging and easy debug strings with embedded R code!)
  • logR: transactional logging to databases and email notifications
  • loggr: logging to files, console
  • logr: logging to files
  • dtq: detailed auditing of data.table queries
  • loggit
  • rlogging
  • log4r
  • rsyslog for POSIX-compatible OSes
  • lgr: a logging package for R built on the back of R6 classes. Supports logging of data in objects.

See also:

https://www.r-bloggers.com/effortless-but-powerful-exception-logging-in-r-loggit-1-0-0-released-on-cran/

CRAN download statistics:

library(cranlogs)
library(data.table)
res <- cran_downloads(when = "last-month", packages = c("futile.logger", "logging", "logR", "logr", "loggr", "dtq", "loggit", "rlogging", "log4r", "rsyslog", "luzlogr", "debugme", "plogr", "logger", "lgr"))
setDT(res)
res[, .(.N, downloads = sum(count)), by = .(package)][downloads > 0,][order(-downloads),]

shows two major packages and a newcomer (debugme) - last updated July 22, 2022 (with lgr, logR added):

          package  N downloads
 1: futile.logger 30    178068
 2:         plogr 30     88917
 3:        logger 30     25768
 4:       logging 30     25201
 5:           lgr 30     14701
 6:       debugme 30     14253
 7:         log4r 30     13096
 8:          logr 30      1470
 9:        loggit 30       729
10:       rsyslog 30       647
11:       luzlogr 30       378

aryoda avatar Mar 20 '19 20:03 aryoda

To support the logging package a simple call should work:

set.logging.functions(logging::logerror, logging::logwarn, logging::loginfo)

Required code changes:

  • Modify the zzz.R for logging support as default (with futile.logger having higher prio)
  • Add convenience functions use.log.pkg.futile.logger + use.log.pkg.logging.pkg + use.log.pkg.tryCatchLog (or "activate", "use", "enable", "set"... as prefix)

To experiment with the logging levels try

# default logging level is INFO
tryCatchLog(log(-1), silent.warnings = T)
logging::setLevel("WARN")
tryCatchLog(log(-1), silent.warnings = T)
logging::setLevel("ERROR")
tryCatchLog(log(-1), silent.warnings = T)

aryoda avatar Oct 04 '19 10:10 aryoda

The debugme package is a good newcomer and supporting it as logging framework out-of-the-box looks straight-forward.

Implementation hints:

There is one central public debug function which supports printing log messages according to different severity levels by prepending a certain number of exclamation marks:

get_log_levels <- function() {
  c(FATAL   = 1,
    ERROR   = 2,
    WARNING = 3,
    INFO    = 4,
    DEBUG   = 5,
    VERBOSE = 6
    )
}

get_msg_debug_levels <- function(x) {
  m <- re_match(x, "^!DEBUG-(?<level>[^\\s]+)\\s+")
  if (! is.na(m$.match)) {
    wh <- match(m$level, names(get_log_levels()))
    if (is.na(wh)) {
      warning("Unknown debug level: `", m$level, "`")
      0
    } else {
      wh
    }
  } else {
    m <- re_match(x, "^(!+)DEBUG\\s+")
    if (is.na(m[1,1])) 0 else nchar(m[1,1])
  }
}

Source: https://github.com/r-lib/debugme/blob/master/R/debug.R

Log levels are documented in the vignette:

https://cran.r-project.org/web/packages/debugme/debugme.pdf

To organize the log messages into log levels, you can start the !DEBUG token with multiple ! char-acters. You can then select the desired level of logging via ! characters before the package name in the DEBUGME environment variable. E.g. DEBUGME=!!mypackagemeans that only debug messages with two or less ! marks will be printed.

aryoda avatar Mar 21 '20 16:03 aryoda

Currently it is also not possible to switch between different logging frameworks in tryCatchLog except calling the "low-level" tryCatchLog::set.logging.functions().

If would be good to provide convenience functions to have an explicit public API, eg.:

set.logging.framework.internal() # tryCatchLog = same as calling tryCatchLog::set.logging.functions() with the default arguments
set.logging.framework.futile.logger()
set.logging.framework.xyz()

aryoda avatar Dec 12 '21 13:12 aryoda

I have added the logger package (https://github.com/daroczig/logger) to the watch list and updated the CRAN download statstics:

library(cranlogs)
library(data.table)
res <- cran_downloads(when = "last-month", packages = c("futile.logger", "logging", "logR", "logr", "loggr", "dtq", "loggit", "rlogging", "log4r", "rsyslog", "luzlogr", "debugme", "plogr", "logger"))
setDT(res)
res[, .(.N, downloads = sum(count)), by = .(package)][downloads > 0,][order(-downloads),]
# Dec 14, 2021:
# package  N downloads
# 1: futile.logger 30    121455
# 2:         plogr 30     94182
# 3:        logger 30     23239
# 4:       logging 30     20735
# 5:         log4r 30     18342
# 6:       debugme 30     11725
# 7:        loggit 30      5176
# 8:          logr 30      1079
# 9:       rsyslog 30       790
# 10:     luzlogr 30        467

aryoda avatar Dec 14 '21 15:12 aryoda

The major preparation for supporting more logging frameworks was done with #74 for lgr by extending the API (and improving the internal code for that)...

aryoda avatar Jul 25 '22 07:07 aryoda