上下文
正如 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 中的调用堆栈似乎在引发错误然后处理时被清除(我可能错了,所以欢迎提供任何信息),因此我们需要在错误发生时捕获错误。
脚本出错
我使用了您之前关于 where 和 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\""
希望这可能会有所帮助。