在R中的tryCatch'ed错误上获取堆栈跟踪

时间:2013-03-07 21:51:49

标签: r error-handling

这与其他一些问题有关,但我似乎无法弄清楚如何应用答案,所以我问了一个新问题。

我试图从一段看起来像这样的代码中找出一个无法解释的错误:

tryCatch(MainLoop(), 
  error=function(e) { fatal(lgr, paste('caught fatal error:', as.character(e))); 
                      exit.status <<- 1 })

问题在于错误似乎与库函数中隐藏的内容有关:

Error in nrow(x): (subscript) logical subscript too long

nrow不在我的代码中,因为上面的C级错误仅适用于我的nrow次调用中从未发生的索引类型。

所以我真的想从tryCatch内获得堆栈跟踪。这是一个类似的问题:

x <- function() { y(); }
y <- function() { z(); }
z <- function() { stop("asdf") }

> x()
Error in z() : asdf
> tryCatch(x(), error=function(e) { print(conditionCall(e)) } )
z()
> tryCatch(x(), error=function(e) { dump.frames() } )
> last.dump
$`tryCatch(x(), error = function(e) {
    dump.frames()
})`
<environment: 0x1038e43b8>

$`tryCatchList(expr, classes, parentenv, handlers)`
<environment: 0x1038e4c60>

$`tryCatchOne(expr, names, parentenv, handlers[[1]])`
<environment: 0x1038e4918>

$`value[[3]](cond)`
<environment: 0x1038ea578>

attr(,"error.message")
[1] "asdf"
attr(,"class")
[1] "dump.frames"

如何获得包含对y()的调用的堆栈跟踪?我是否必须停止使用tryCatch?什么是更好的方式?

4 个答案:

答案 0 :(得分:16)

对于交互式使用,可以trace(stop, quote(print(sys.calls())))在调用stop()时打印调用堆栈。

来自?tryCatch

 The function 'tryCatch' evaluates its expression argument in a
 context where the handlers provided in the '...'  argument are
 available.

,而

 Calling handlers are established by 'withCallingHandlers'...
 the handler is called... in the context where the condition
 was signaled...

所以

>     withCallingHandlers(x(), error=function(e) print(sys.calls()))
[[1]]
withCallingHandlers(x(), error = function(e) print(sys.calls()))

[[2]]
x()

[[3]]
y()

[[4]]
z()

[[5]]
stop("asdf")

[[6]]
.handleSimpleError(function (e) 
print(sys.calls()), "asdf", quote(z()))

[[7]]
h(simpleError(msg, call))

Error in z() : asdf

如果存在内部tryCatch

,则会受到阻碍
withCallingHandlers({
    tryCatch(x(), error=function(e) stop("oops"))
}, error=function(e) print(sys.calls()))

因为我们只有在tryCatch“处理”错误后才能访问调用堆栈。

答案 1 :(得分:3)

是的,有可能。它在编码方面不是太优雅,但在输出方面非常有用! 欢迎提出任何意见!

我把它放在我的misc包中,如果你想要文档,可以从那里使用它。 https://github.com/brry/berryFunctions/blob/master/R/tryStack.R 计划即将发布下一个CRAN版本,直到那时:

devtools::install_github("brry/berryFunctions")
# or use:
source("http://raw.githubusercontent.com/brry/berryFunctions/master/R/instGit.R")
instGit("brry/berryFunctions")

library(berryFunctions)
?tryStack

这里是快速参考:

tryStack <- function(
expr,
silent=FALSE
)
{
tryenv <- new.env()
out <- try(withCallingHandlers(expr, error=function(e)
  {
  stack <- sys.calls()
  stack <- stack[-(2:7)]
  stack <- head(stack, -2)
  stack <- sapply(stack, deparse)
  if(!silent && isTRUE(getOption("show.error.messages"))) 
    cat("This is the error stack: ", stack, sep="\n")
  assign("stackmsg", value=paste(stack,collapse="\n"), envir=tryenv)
  }), silent=silent)
if(inherits(out, "try-error")) out[2] <- tryenv$stackmsg
out
}

lower <- function(a) a+10
upper <- function(b) {plot(b, main=b) ; lower(b) }

d <- tryStack(upper(4))
d <- tryStack(upper("4"))
cat(d[2])
  

d&lt; - tryStack(upper(“4”))

     

这是错误堆栈:

     

tryStack(upper(“4”))

     

上( “4”)

     

降低(b)

     

+ 10的错误:二元运算符的非数字参数

答案 2 :(得分:0)

我是evaluate::try_capture_stack()的粉丝。

x <- function() {
  y()
}
y <- function() {
  z()
}
z <- function() {
  stop("asdf")
}
env <- environment()
e <- evaluate::try_capture_stack(quote(x()), env)
names(e)
#> [1] "message" "call"    "calls"
e$calls
#> [[1]]
#> x()
#> 
#> [[2]]
#> y()
#> 
#> [[3]]
#> z()
#> 
#> [[4]]
#> stop("asdf")

答案 3 :(得分:0)

我参加聚会有点晚了,但是我发现最好的方法是在您尝试使用的函数中使用退出处理程序。

main <- function()
{
  on.exit({
    msg <- capture.output(traceback())
    if (msg != "No traceback available ")
    {
      print(msg)
    }
  }
  )
  # rest of code
}

withCallingHandlers(
  expr =
    {
      main()
    },
  error = function(e) 
  {
    print(e)
  }
)