How to show error location in tryCatch?

Displaying error locations with options(show.error.locations = TRUE) doesn't seem to work when handling exceptions with tryCatch . I am trying to show the location of the error, but I do not know how:

 options(show.error.locations = TRUE) tryCatch({ some_function(...) }, error = function (e, f, g) { e <<- e cat("ERROR: ", e$message, "\nin ") print(e$call) }) 

If I then look at the variable e , the location does not look like it:

 > str(e) List of 2 $ message: chr "missing value where TRUE/FALSE needed" $ call : language if (index_smooth == "INDEX") { rescale <- 100/meanMSI[plotbaseyear] ... - attr(*, "class")= chr [1:3] "simpleError" "error" "condition" 

If I do not delay the error, it prints to the console along with the source file and line number. How to do this with tryCatch?

+5
source share
2 answers

You can use traceback () in the error handler to display the call stack. Errors in tryCatch do not produce line numbers. See Also help for tracking. If you use your tryCatch arguments defensively, this will help you narrow down the error spot.

Here is a working example:

 ## Example of Showing line-number in Try Catch # set this variable to "error", "warning" or empty ('') to see the different scenarios case <- "error" result <- "init value" tryCatch({ if( case == "error") { stop( simpleError("Whoops: error") ) } if( case == "warning") { stop( simpleWarning("Whoops: warning") ) } result <- "My result" }, warning = function (e) { print(sprintf("caught Warning: %s", e)) traceback(1, max.lines = 1) }, error = function(e) { print(sprintf("caught Error: %s", e)) traceback(1, max.lines = 1) }, finally = { print(sprintf("And the result is: %s", result)) }) 
0
source

Context

As Willem van Leesburg noted, it is not possible to use the traceback() function to display where an error occurred with tryCatch() , and as far as I know, there is currently no practical way to save the error position with basic functions in R when using tryCatch .

The idea of ​​a separate error handler

The possible solution that I found consists of two parts, the main one of which is to write an error handler, similar to the Chrispy method , from "tracing the print stack and continuing after an error in R" , which creates a log with the error position. The second part writes this output to a variable, similar to what was suggested by Ben Bolker in "Is it possible to redirect console output to a variable" .

The call column in R seems to be cleared when an error occurs, and then processed (maybe I'm wrong, so any information is welcome), so we need to fix the error during its occurrence.

Script with an error

I used an example from one of your previous questions regarding where the error is R , with the following function stored in a file called "TestError.R", which I call in my example below:

 # TestError.R f2 <- function(x) { if (is.null(x)) "x is Null" if (x==1) "foo" } f <- function(x) { f2(x) } # The following line will raise an error if executed f(NULL) 

Bug tracking function

This is a feature that I adapted for Chrispy code, as I mentioned above. After execution, if an error occurs, the code below will print where the error occurred, in the case of the above function, it will print: "Error occuring: Test.R#9: f2(x)" and "Error occuring: Test.R#14: f(NULL)" means an error caused by a malfunction of the function f(NULL) on line 14, which refers to the function f2() on line 9

 # Error tracing function withErrorTracing = function(expr, silentSuccess=FALSE) { hasFailed = FALSE messages = list() warnings = list() errorTracer = function(obj) { # Storing the call stack calls = sys.calls() calls = calls[1:length(calls)-1] # Keeping the calls only trace = limitedLabels(c(calls, attr(obj, "calls"))) # Printing the 2nd and 3rd traces that contain the line where the error occured # This is the part you might want to edit to suit your needs print(paste0("Error occuring: ", trace[length(trace):1][2:3])) # Muffle any redundant output of the same message optionalRestart = function(r) { res = findRestart(r); if (!is.null(res)) invokeRestart(res) } optionalRestart("muffleMessage") optionalRestart("muffleWarning") } vexpr = withCallingHandlers(withVisible(expr), error=errorTracer) if (silentSuccess && !hasFailed) { cat(paste(warnings, collapse="")) } if (vexpr$visible) vexpr$value else invisible(vexpr$value) } 

Saving error position and message

We call the script TestError.R above and fix the printed result in a variable called errorStorage here, with which we can work later or just display.

 errorStorage <- capture.output(tryCatch({ withErrorTracing({source("TestError.R")}) }, error = function(e){ e <<- e cat("ERROR: ", e$message, "\nin ") print(e$call) })) 

Therefore, we store the value of e with the call and message, as well as with the location of the error location. The errorStorage output should be as follows:

 [1] "[1] \"Error occuring: Test.R#9: f2(x)\" \"Error occuring: Test.R#14: f(NULL)\"" [2] "ERROR: argument is of length zero " [3] "in if (x == 1) \"foo\"" 

Hoping this can help.

0
source

Source: https://habr.com/ru/post/1259821/


All Articles