如何在tryCatch中显示错误位置?

时间:2016-11-16 10:27:09

标签: r exception-handling try-catch

使用options(show.error.locations = TRUE)处理异常时,使用tryCatch显示错误位置似乎不起作用。我试图显示错误的位置,但我不知道如何:

options(show.error.locations = TRUE)

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

如果我查看变量e,那么该位置似乎不存在:

> 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"

如果我没有捕获错误,它将与源文件和行号一起打印在控制台上。如何使用tryCatch?

2 个答案:

答案 0 :(得分:2)

<强>上下文

如Willem van Doesburg所述,无法使用traceback() function来显示tryCatch()发生错误的位置,据我所知,目前还没有实用的方法使用tryCatch 时,在R 中存储基本函数的错误位置。

单独错误处理程序的想法

我找到的可能解决方案由两部分组成,主要部分是编写一个类似于Chrispy from "printing stack trace and continuing after error occurs in R"的错误处理程序,它生成一个包含错误位置的日志。 第二部分是将此输出捕获到变量中,类似于Ben Bolker in "is it possible to redirect console output to a variable"建议的那样。

当出现错误然后处理时,R中的调用堆栈似乎被清除(我可能错了所以欢迎任何信息),因此我们需要在错误发生时捕获它。

有错误的脚本

我使用了前面一个问题中的一个示例,其中R error occured将以下函数存储在一个名为“TestError.R”的文件中,我在下面的示例中调用该文件:

# 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)

错误跟踪功能

这是我在上面提到的Chrispy的代码中修改的功能。 执行时,如果出现错误,下面的代码将打印发生错误的位置,在上述功能的情况下,它将打印: "Error occuring: Test.R#9: f2(x)""Error occuring: Test.R#14: f(NULL)"表示错误是由于第14行的f(NULL)函数出现问题导致第9行引用f2()函数

# 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)
}

存储错误排名和消息

我们调用上面的脚本TestError.R并在变量中捕获打印输出,此处称为errorStorage,我们可以稍后处理或简单地显示。

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

因此,我们将e的值与呼叫和消息以及错误位置的位置保持一致。 errorStorage输出应如下所示:

[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\""

希望这可能有所帮助。

答案 1 :(得分:0)

您可以在错误处理程序中使用traceback()来显示调用堆栈。 tryCatch中的错误不会产生行号。另请参阅回溯中的help。如果您以防御方式使用tryCatch语句,这将有助于缩小错误的位置。

这是一个有效的例子:

## 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))
})