我在服务器上运行的R中有许多无人值守的批处理作业,我必须在运行后分析作业失败。
我正在尝试捕获错误以记录它们并优雅地从错误中恢复但我无法获得堆栈跟踪(traceback
)来记录导致R命令的代码文件名和行号错误。一个(愚蠢的)可重复的例子:
f <- function() {
1 + variable.not.found # stupid error
}
tryCatch( f(), error=function(e) {
# Here I would log the error message and stack trace (traceback)
print(e) # error message is no problem
traceback() # stack trace does NOT work
# Here I would handle the error and recover...
})
运行上面的代码会产生以下输出:
f()中的simpleError:object&#39; variable.not.found&#39;找不到
无可追溯
回溯不可用,原因记录在R帮助(?traceback
)中:
通过try或tryCatch捕获的错误不会生成 回溯,所以打印的是最后一个的调用序列 未被捕获的错误,并不一定是最后一次错误。
换句话说:使用tryCatch
捕获错误确实会导致堆栈跟踪!
我怎么能
THX很多!
答案 0 :(得分:3)
很抱歉答案很长,但我想在一个答案中总结所有知识和参考资料!
tryCatch
将“调用堆栈”“展开”到tryCatch
调用,以便traceback
和sys.calls
不再包含完整堆栈跟踪以标识源导致错误或警告的代码行。
tryCatch
aborts the execution if you catch a warning通过传递warning
条件的处理函数。如果您只想记录警告,则无法正常继续执行。
dump.frames
写入堆栈跟踪的评估环境(框架)以允许事后调试(=检查每个函数调用中可见的变量值),但dump.frames
"forgets" to save the workspace too if you set the parameter to.file = TRUE
。因此可能缺少重要的物体。
找到一个简单的日志记录框架,因为R不支持开箱即用的正确日志记录
使用源代码行丰富堆栈跟踪。
使用withCallingHandlers
代替tryCatch
获取指向引发错误或警告的源代码行的完整堆栈跟踪。
仅在withCallingHandlers
内(不在tryCatch
内)捕获警告,因为它只调用处理函数但不会更改程序流。
使用withCallingHandlers
环绕tryCatch
以捕获并处理所需的错误。
使用带有参数dump.frames
的{{1}}将转储写入名为to.file = FALSE
的全局变量,并通过调用{{1}将其与全局环境一起保存到文件中}。
使用日志框架,例如: G。包last.dump
。
当您设置save.image
时,R会跟踪源代码引用。您可以将此选项添加到futile.logger
文件中,也可以使用设置此选项的启动R脚本,然后使用options(keep.source = TRUE)
实际的R脚本。
要使用跟踪的源代码行丰富堆栈跟踪,您可以使用未记录的(但广泛使用的)函数.Rprofile
。
要从堆栈跟踪中过滤掉R内部函数调用,您可以删除所有没有源代码行引用的调用。
您应该使用此代码段:
,而不是使用source
limitedLabels
tryCatch
)我已经实现了一个包含上述所有概念的简单包。
它使用library(futile.logger)
tryCatch(
withCallingHandlers(<expression>,
error = function(e) {
call.stack <- sys.calls() # is like a traceback within "withCallingHandlers"
dump.frames()
save.image(file = "last.dump.rda")
flog.error(paste(e$message, limitedLabels(call.stack), sep = "\n"))
}
warning = <similar to error above>
}
error = <catch errors and recover as you would do it normally>
# warning = <...> # never do this here since it stops the normal execution like an error!
finally = <your clean-up code goes here>
}
包提供函数tryCatchLog
。
用法:
tryCatchLog
您可以在github上找到免费的源代码:
https://github.com/aryoda/tryCatchLog
你也可以futile.logger
tryCatchLog
function而不是使用完整的套餐。
请参阅提供大量评论的demo file来解释其工作原理。
library(tryCatchLog) # or source("R/tryCatchLog.R")
tryCatchLog(<expression>,
error = function(e) {
<your error handler>
})
替换使用功能记录警告和错误,以便在try catch执行多次尝试(重试),例如: G。用于访问不可靠的网络驱动器:
source
函数,不依赖于其他包,这些包也使用tryCatch
丰富了对调用堆栈的源代码引用:
http://adv-r.had.co.nz/Exceptions-Debugging.html
A Warning About warning() - avoid R's warning feature
In R, why does withCallingHandlers still stops execution?
How to continue function when error is thrown in withCallingHandlers in R
Can you make R print more detailed error messages?
How can I access the name of the function generating an error or warning?
How do I save warnings and errors as output from a function?
options(error=dump.frames) vs. options(error=utils::recover)
General suggestions for debugging in R
Suppress warnings using tryCatch in R
R Logging display name of the script
Background information about the "srcrefs" attribute (Duncan Murdoch)
答案 1 :(得分:2)
traceback
函数可用于打印/保存当前堆栈跟踪,但您必须指定一个整数参数,它是从顶部省略的堆栈帧数(可以是{{1} })。这可以在0
块内或其他任何地方完成。假设这是文件tryCatch
的内容:
t.r
当您将此文件导入R并运行f <- function() {
x <- 1
g()
}
g <- function() {
traceback(0)
}
时,您将获得堆栈跟踪:
3:t.r#7的追溯(0) 2:g()at t.r#3
1:f()
,其中包含每个条目的文件名和行号信息。您将获得源自f
实现的多个堆栈帧,并且您不能通过为tryCatch
指定非零参数来跳过它们,但实际上这将在{ {1}}更改。
文件名和行号信息(源引用)仅适用于已经过解析以保留源引用的代码(默认情况下为traceback
代码,但不包括代码)。堆栈跟踪将始终具有调用表达式。
堆栈跟踪由tryCatch
打印(无需在其上调用source
)。
对于记录常规错误,使用traceback
有时很有用,然后不需要修改导致错误的代码。