, ,

I will be pushing a new version of futile.logger (version 1.5) to CRAN in January. This version introduces a number of enhancements and fixes some bugs. It will also contain at least one breaking change. I am making the release process public, since the package is now used in a number of other packages. If you use futile.logger, this is your opportunity to influence the direction of the package and prepare for changes. Please use the github issue tracker for discussion.

There are two main themes for enhancements: 1) integration with the signal conditions, and 2) supporting multiple appenders with different  thresholds.

Hijacking the signal system

Currently, futile.logger is unaware of the signal system in R. The only tie-in is with ftry, which catches a warning or error and prints a message. Unfortunately, the behavior is different from try. This release will make ftry consistent with try. This is a breaking change, so if you use ftry in your code, it will no longer halt processing.

In addition to this fix, futile.logger will now have better integration with the signal system. Currently, if a function emits a warning or an error, these are printed to the screen. It would be convenient if futile.logger can capture these signals and associate them to the correct log levels, i.e. warning to WARN and error to ERROR.

My proposal is to create a hijack_signal_handlers function to override the existing signal handlers. This function can be called at the top of a script or within the .onLoad function of a package. Once called, any warnings or errors would be captured and handled by futile.logger. The implementation would look like this, giving granular control of whether to hijack just warning, errors, or both:

hijack_signal_handlers <- function(warning=TRUE, error=TRUE) {
  if (warning) {
# Override warning handler
if (error) {
# Override error handler

One issue I see with this function is when used in a package’s .onLoad. Suppose a user requires package A and B. These don’t use futile.logger. Now the user requires package C, which calls hijack_signal_handlers in its .onLoad. When this occurs, warnings and errors emitted from packages A and B would also be captured by futile.logger. From my perspective, this is probably a good thing, but I can appreciate why others may not want this behavior. 

Emitting signals

The other half of the signal handler puzzle is being able to emit signals from futile.logger. For this case, we want flog.warn to emit a warning signal and flog.error to emit an error signal. One signature looks like

flog.warn(message, emit=TRUE)

meaning that by default no signal is emitted. This would work for flog.warn, flog.error, and flog.fatal (could map to error as well).

I have mixed feelings about this use case. Part of me says if futile.logger hijacks the signal system, then just use stop and futile.logger will catch it. On the other hand that seems roundabout and less capable than writing flog.error(message, emit=TRUE) or whatever.

Really my main concern is what happens when these two systems work together? Will they play nice or will an error be emitted twice (likely)? If not, then there is more logic that has to be built in, which ultimately adds complexity and wastes cycles. Any input here is encouraged!