daroczig / logger

A lightweight, modern and flexible, log4j and futile.logger inspired logging utility for R
https://daroczig.github.io/logger
249 stars 38 forks source link

[Help] Piping differnt log_level to distinct outputs #128

Closed pinduzera closed 9 months ago

pinduzera commented 9 months ago

Is there a way to make different log_levels to go to different places? My goal is to do anything more severe or equal to logger::ERROR go to stderr() and anything less harmful goes to stdout()

I've tried using 2 threshold but then it would replicate the message:

logger::log_threshold(logger::INFO, index = 1)
logger::log_appender(logger::appender_stdout, index = 1)
logger::log_threshold(logger::ERROR, index = 2)
logger::log_appender(logger::appender_stderr, index = 2)

logger::log_info("hello")  ## pipe only to stdout

# INFO [2023-10-26 16:03:27] hello ## stdout

logger::log_error("hello") ## pipes to STDER & STDOUT
# ERROR [2023-10-26 16:03:45] hello ## stdout
# ERROR [2023-10-26 16:03:45] hello ## stderr
daroczig commented 9 months ago

log_threshold only compares the log level with a minimal threshold: https://github.com/daroczig/logger/blob/master/R/logger.R#L36-L38

So you cannot do a range / unique array filtering on log levels, unfortunately.

Any chance you could use namespaces instead?

If that's not viable, then I'd be interested in hearing more about the use case and then figure out a way of dropping the threshold idea and come up with a log level filtering approach.

pinduzera commented 9 months ago

The use case is mainly that I have another System that calls R to make a pretty integration among the two. It launches an RScript to do stuff and capture the R's output. The things, all I can capture using that system are stderr() or stdout() and then log on that system own logging system, but the thing is that R's Warning aren't necessarily that severe and by default they go to stderr(), which is not nice in my case.

I've been trying to use namespaces but I don't have a nice way of creating namespaces (and the obsolete namespace package is too hacky) within an RScript, the best I could achieve is having an environment.

I was thinking something that allows the appender to have a log_level threshold on itself

appender_custom <- function(lines, level) { 
if(level > ERROR) {
        cat(...)
    } else {
        cat(..., file = stderr() )
    }
}
daroczig commented 9 months ago

Thanks for the details!

Regarding the namespaces: I was referring to the namespace arg of the logger fns (similar to index).

pinduzera commented 9 months ago

I was actually able to achieve the goal with the namespaces tip, i thought it was related to the namespace:package, not logger's own namespace. I can do this way:

logger::log_threshold(logger::INFO, namespace = "nsInfo")
logger::log_appender(logger::appender_stdout, namespace = "nsInfo")

## This Namespace goes to stderr the default
logger::log_threshold(logger::ERROR, namespace = "nsError")

MyLogger <- function(msg, level = logger::ERROR){

  if (level <= logger::ERROR) {
    logger::log_level(level, msg, namespace = "nsError")
  } else {
    logger::log_level(level, msg, namespace = "nsInfo")
  }
  invisible()
}

MyLogger(msg = "My Error", level = logger::ERROR) 
# ERROR [2023-10-26 17:44:39] My Error
MyLogger(msg = "My Message", level = logger::INFO) 
# INFO [2023-10-26 17:44:40] My Message