s-fleck/lgr

Print the name of the logger in the log

Fuco1 opened this issue · 5 comments

Fuco1 commented

I'm quite fond of using "complicated" logger hierarchies for tracing complicated algorithms, where I can enable/disable parts of the code selectively (by rising/lowering the log levels of various sub-loggers).

However sometimes I get lost in where the messages are coming from. It would be nice if I could log the logger name in the output (mostly using the format layout). I'm used to this from log4j and miss it a little.

Since I ship all my logs to elastic it would also enable me to filter only logs related to a specific part of the application in a very simple way (granted, adding some meta-data directly as asked in #40 would maybe serve this purpose better). But as a low-effort solution it would be sufficient.

I'm honestly kinda surprised that I didn't include that in format.LogEvent. Not sure yet how to include it in JSON logging (API-wise), so give me some time to think about it.

Meanwhile, Filters are again an easy workaround to this problem:

library(lgr)
lg <- get_logger("test/logger")
f <- function(event) {
  event[["lgr"]] <- event$logger
  TRUE
} 
lg$add_filter(f)
lg$info("test")

Sadly you can not use the name logger for the custom field.
A nicer solution would be subclassing LayoutJson:

LayoutJson2 <- R6::R6Class(
  inherit = lgr::LayoutJson
  ,
  public = list(
    format_event = function(event) {
      vals <- c(get("values", event), logger = get("logger", event))   # here is where the magic happens
      fmt  <- get("timestamp_fmt", self)

      if (!is.null(fmt)){
        vals[["timestamp"]] <- fmt_timestamp(vals[["timestamp"]], fmt)
      }

      do.call(
        jsonlite::toJSON,
        args = c(list(x = vals), get(".toJSON_args", private))
      )
    }
  )
)

lg <- get_logger("test/logger")
lg$add_appender(AppenderConsole$new(layou = LayoutJson2$new()))

lg$info("test")

Might be that this will be the default behaviour in future versions anyways

Ah! format.LogEvent() alread DOES support what you are requesting, its just missing from the documentation! The token you need is %g:

lg <- lgr::get_logger("test/logger")
basic_config(console_fmt = "%g ~ %L [%t] %m")
lg$info("test")
Fuco1 commented

Oh, nice! I think I was mostly interested in this for the interactive case (i.e. format logger), but the json extra field would be nice as well.

I haven't yet worked with the R6 system so the code is a bit magical to me, but it seems like a good investment to spent one hour to read around. There's more packages around using it.

R6 is pretty cool if you need an object system with mutable objects, so if you have used Java before, R6 classes should be pretty familiar.

the internal code of lgr uses get() instead of $ a lot in places where performance is important. That makes some part of the code a bit confusing/obscure. In the example above get("values", event) is the same as just event$values, but a few ms faster.

Seems that i forgot to close this one