打印堆栈跟踪并在R中发生错误后继续

Ali*_*ell 21 debugging r

我正在写一些R代码调用可能失败的其他代码.如果是这样,我想打印一个堆栈跟踪(追踪出错的地方),然后继续进行.但是,traceback()函数仅提供有关未捕获异常的信息.我可以通过涉及tryCatch和dump.frames的相当复杂,纯粹的构造获得我想要的结果,但是没有更简单的方法吗?

Bob*_*ght 19

我在一周前编写了这段代码,以帮助我找出主要来自非交互式R会话的错误.它仍然有点粗糙,但它打印出一个堆栈跟踪并继续.让我知道如果这是有用的,我会对你如何使这个更有用的信息感兴趣.我也可以通过更清晰的方式获取这些信息.

options(warn = 2, keep.source = TRUE, error = quote({
  # Debugging in R
  #   http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/index.shtml
  #
  # Post-mortem debugging
  #   http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR/pmd.shtml
  #
  # Relation functions:
  #   dump.frames
  #   recover
  # >>limitedLabels  (formatting of the dump with source/line numbers)
  #   sys.frame (and associated)
  #   traceback
  #   geterrmessage
  #
  # Output based on the debugger function definition.

  # TODO: setup option for dumping to a file (?)
  # Set `to.file` argument to write this to a file for post-mortem debugging    
  dump.frames()  # writes to last.dump
  n <- length(last.dump)
  if (n > 0) {
    calls <- names(last.dump)
    cat("Environment:\n", file = stderr())
    cat(paste0("  ", seq_len(n), ": ", calls), sep = "\n", file = stderr())
    cat("\n", file = stderr())
  }

  if (!interactive()) q()
}))
Run Code Online (Sandbox Code Playgroud)

PS:您可能不希望warn = 2(警告转换为错误)


Ali*_*ell 10

我最后编写了一个通用记录器,当调用标准的R"message","warning"和"stop"方法时,它会生成类似Java的日志记录消息.它包括时间戳,以及警告及以上的堆栈跟踪.

非常感谢Man Group允许分发这个!还要感谢鲍勃·奥尔布赖特,他的回答让我对我正在寻找的东西有所帮助.

withJavaLogging = function(expr, silentSuccess=FALSE, stopIsFatal=TRUE) {
    hasFailed = FALSE
    messages = list()
    warnings = list()
    logger = function(obj) {
        # Change behaviour based on type of message
        level = sapply(class(obj), switch, debug="DEBUG", message="INFO", warning="WARN", caughtError = "ERROR",
                error=if (stopIsFatal) "FATAL" else "ERROR", "")
        level = c(level[level != ""], "ERROR")[1]
        simpleMessage = switch(level, DEBUG=,INFO=TRUE, FALSE)
        quashable = switch(level, DEBUG=,INFO=,WARN=TRUE, FALSE)

        # Format message
        time  = format(Sys.time(), "%Y-%m-%d %H:%M:%OS3")
        txt   = conditionMessage(obj)
        if (!simpleMessage) txt = paste(txt, "\n", sep="")
        msg = paste(time, level, txt, sep=" ")
        calls = sys.calls()
        calls = calls[1:length(calls)-1]
        trace = limitedLabels(c(calls, attr(obj, "calls")))
        if (!simpleMessage && length(trace) > 0) {
            trace = trace[length(trace):1]
            msg = paste(msg, "  ", paste("at", trace, collapse="\n  "), "\n", sep="")
        }

        # Output message
        if (silentSuccess && !hasFailed && quashable) {
            messages <<- append(messages, msg)
            if (level == "WARN") warnings <<- append(warnings, msg)
        } else {
            if (silentSuccess && !hasFailed) {
                cat(paste(messages, collapse=""))
                hasFailed <<- TRUE
            }
            cat(msg)
        }

        # 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),
            debug=logger, message=logger, warning=logger, caughtError=logger, error=logger)
    if (silentSuccess && !hasFailed) {
        cat(paste(warnings, collapse=""))
    }
    if (vexpr$visible) vexpr$value else invisible(vexpr$value)
}
Run Code Online (Sandbox Code Playgroud)

要使用它,只需将其包裹在您的代码中:

withJavaLogging({
  // Your code here...
})
Run Code Online (Sandbox Code Playgroud)

为了在没有错误的情况下更安静的输出(对测试有用!),设置silentSuccess标志.只有在发生错误时才会输出消息,以便为失败提供上下文.

要实现原始目标(转储堆栈跟踪+继续),只需使用try:

try(withJavaLogging({
  // Your code here...
}, stopIsFatal=FALSE))
Run Code Online (Sandbox Code Playgroud)


Chr*_*don 8

如果对选项(错误...)触发的内容感兴趣,您也可以这样做:

options(error=traceback)
Run Code Online (Sandbox Code Playgroud)

据我所知,它完成了鲍勃建议的解决方案所做的大部分工作,但具有更短的优势.

(根据需要随意与keep.source = TRUE,warn = 2等结合使用.)

  • 不幸的是,我需要继续,即在try()块中运行,因此它不会触发选项(error = ...). (2认同)

Dir*_*tel 5

你试过吗?

 options(error=recover)
Run Code Online (Sandbox Code Playgroud)

设置?钱伯斯的"数据分析软件"提供了一些有用的调试提示.