Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

send R diagnostic messages to stdout instead stderr

Looking for an options which let me to redirect R diagnostic messages (produces by message()) to stdout, not stderr as it is by default.

message manual states:

The default handler sends the message to the stderr() connection.

So the question is how can I change this default behavior? still leaving redirection of warning() and stop() intact.

Already tried sink type='message' but it redirects all (messages, warnings, errors).

If anyone is willing to test, this is sample script exec_test.R:

print("using print")
cat("using cat\n")
message("using message")
warning("using warning")
stop("using stop")
q("no")

which then will be executed by:

Rscript exec_test.R 1>> exec_test.Rout 2>> exec_test_error.Rout

I don't what to use 2>&1 because my script produce tons of messages and very rarely the real errors so I need to store those logs in separate files.

like image 555
jangorecki Avatar asked Aug 14 '14 11:08

jangorecki


People also ask

Should warnings go to stderr or stdout?

Warning logs are not errors. None of these should go to stderr by default. Only error logs should go to stderr.

How do I send stderr to stdout?

Understanding the concept of redirections and file descriptors is very important when working on the command line. To redirect stderr and stdout , use the 2>&1 or &> constructs.

How do I output a message in R?

To display ( or print) a text with R, use either the R-command cat() or print(). Note that in each case, the text is considered by R as a script, so it should be in quotes. Note there is subtle difference between the two commands so type on your prompt help(cat) and help(print) to see the difference.

Can stderr be redirected?

The regular output is sent to Standard Out (STDOUT) and the error messages are sent to Standard Error (STDERR). When you redirect console output using the > symbol, you are only redirecting STDOUT. In order to redirect STDERR, you have to specify 2> for the redirection symbol.


3 Answers

Using sink. Here's a modification of your code:

sink(stdout(), type = "message") # sink messages to stdout
print("using print")
cat("using cat\n")
message("using message")
warning("using warning")
sink(NULL, type="message") # close the sink
warning("after ending sink") # this will be the only thing in your err file
q("no")
like image 79
Thomas Avatar answered Oct 18 '22 16:10

Thomas


The OP showed the execution happening via the Rscript command and using some I/O redirection. If you want to use redirection to log everything and only show to console on error, the best method I've found is to use || to check if the script had non-zero exit status before printing to screen:

Rscript myrscript.R > temp.log 2>&1 || cat temp.log

This method relies strictly on the exit code for printing, which only partly gets around message() going to stderr, but I thought this example helpful to mention since messages won't necessarily trigger a non-zero exit status and you can continue to log quietly with this method.

If you'd like to go one step further and keep appending to a single log file, then this will work:

Rscript myrscript.R > temp.log 2>&1 || cat temp.log && cat temp.log >> persistent.log && rm temp.log

The pseudocode for this command is:

  1. Redirect stderr and stdout into temp.log
  2. If command had non-zero exit status then write to screen
  3. Then redirect the contents of temp.log into your persistent.log
  4. Then remove temp.log
like image 24
Steven M. Mortimer Avatar answered Oct 18 '22 14:10

Steven M. Mortimer


While this is very likely not a best practice, you could override message with a version that writes to stdout() by default, right?

message <- function (..., domain = NULL, appendLF = TRUE) 
{
    args <- list(...)
    cond <- if (length(args) == 1L && inherits(args[[1L]], "condition")) {
        if (nargs() > 1L) 
            warning("additional arguments ignored in message()")
        args[[1L]]
    }
    else {
        msg <- .makeMessage(..., domain = domain, appendLF = appendLF)
        call <- sys.call()
        simpleMessage(msg, call)
    }
    defaultHandler <- function(c) {
        cat(conditionMessage(c), file = stdout(), sep = "")
    }
    withRestarts({
        signalCondition(cond)
        defaultHandler(cond)
    }, muffleMessage = function() NULL)
    invisible()
}
like image 39
branch14 Avatar answered Oct 18 '22 14:10

branch14