4

我有以下代码,它会引发错误并使用Hadley Wickhamdump.frames()的建议写入所有帧的转储:

a <- -1
b <- "Hello world!"
bad.function <- function(value)
{
  log(value)                  # the log function may cause an error or warning depending on the value
}

tryCatch( {
             a.local.value <- 42
             bad.function(a)
             bad.function(b)
          },
          error = function(e)
          {
            dump.frames(to.file = TRUE)
          })

当我重新启动 R 会话并加载转储以通过以下方式调试问题时

load(file = "last.dump.rda")
debugger(last.dump)

我在帧中的任何地方都找不到我的变量(a、b、a.local.value)和我的函数“bad.function”。

这使转储对我来说几乎毫无价值。

为了进行体面的事后分析,我必须做什么才能查看所有变量和函数?

的输出debugger是:

> load(file = "last.dump.rda")
> debugger(last.dump)
Message:  non-numeric argument to mathematical functionAvailable environments had calls:
1: tryCatch({
    a.local.value <- 42
    bad.function(a)
    bad.function(b)
2: tryCatchList(expr, classes, parentenv, handlers)
3: tryCatchOne(expr, names, parentenv, handlers[[1]])
4: value[[3]](cond)

Enter an environment number, or 0 to exit  
Selection: 

PS:我正在使用 R3.3.2 和 RStudio 进行调试。

4

2 回答 2

4

2016 年 11 月 20 日更新:请注意,它不是R 错误(参见 Martin Maechler 的回答)。我没有改变我的可重复性答案。所描述的解决方法仍然适用。

概括

如果您想在新的 R 会话中调试批处理作业的错误,我认为dump.frames(to.file = TRUE)目前是 R 中的一种反模式(或可能是一个错误)。

您最好将其替换为

  dump.frames()
  save.image(file = "last.dump.rda")

或者

options(error = quote({dump.frames(); save.image(file = "last.dump.rda")}))

代替

options(error = dump.frames)

因为全局环境(.GlobalEnv=您通常创建对象的用户工作区)然后包含在转储中,而当您直接通过dump.frames(to.file = TRUE).

影响分析

如果没有.GlobalEnv您丢失重要的顶级对象(及其当前值;-)来了解导致错误的代码行为!

尤其是在“非交互式”R 批处理作业中出现错误的情况下,您会迷失方向,.GlobalEnv因为您只能在新启动的(空的)交互式工作区中进行调试,然后您只能访问调用堆栈帧中的对象。

使用上面的代码片段,您可以像往常一样通过以下方式检查导致新 R 工作区中错误的对象值:

load(file = "last.dump.rda")
debugger(last.dump)

背景

的实现在工作空间中dump.frames创建一个变量last.dump,并用调用堆栈的环境填充它(sys.frames()每个环境都包含被调用函数的“局部变量”)。然后它将这个变量保存到一个文件中,使用save().

帧堆栈(调用堆栈)随着函数的每次调用而增长,请参阅?sys.frames

.GlobalEnv 在帧列表中的编号为 0。每个后续函数评估都会将帧堆栈增加 1,并且用于评估该函数的 [...] 环境由 [...] sys.frame 返回并具有适当的索引。

观察.GlobalEnv的索引号为 0。

如果我现在开始调试由问题中的代码生成的转储并选择第 1 帧(不是 0!),我可以看到一个parentenv指向(引用)的变量.GlobalEnv

Browse[1]> environmentName(parentenv)
[1] "R_GlobalEnv"

因此我相信sys.frames不包含 the .GlobalEnv,因此dump.frames(to.file = TRUE)也不包含 ,因为它只存储 thesys.frames而没有 的所有其他对象.GlobalEnv

也许我错了,但这看起来像是一个不需要的效果,甚至是一个错误。欢迎讨论!

参考

https://cran.r-project.org/doc/manuals/R-exts.pdf

节选自第4.2 节调试 R 代码(第 96 页):

因为 last.dump 可以稍后查看,甚至可以在另一个 R 会话中查看,所以即使对于 R 的批量使用,也可以进行事后调试。我们确实需要安排保存转储:这可以使用命令行标志 --save 在运行结束时保存工作区,或者通过诸如

选项(错误 = 报价({dump.frames(to.file=TRUE); q()}))

于 2016-11-04T21:06:58.207 回答
2

请注意,与R Core 团队合作通常比仅仅告诉 R 有错误更有效率。在这里,它显然没有错误,因为它的行为与记录的完全一样。

如果您以交互方式工作也没有问题,因为您可以在那里完全访问您的工作区(可能是LARGE),因此该问题仅适用于批处理作业(如您所提到的)。

我们宁愿在这里缺少的功能 和功能请求(和错误报告!)应该发生在 R 错误站点(又名 _'R bugzilla')上,https ://bugs.r-project.org/ ...通常但是在阅读了 R 网站上的相应页面后: https://www.r-project.org/bugs.html

请注意,R bugzilla 是可搜索的,在目前的情况下,您很快就会发现 Andreas Kersting 提出了一个不错的建议(即作为愿望,而不是声称存在错误), https://bugs.r-project.org /bugzilla/show_bug.cgi?id=17116 因此我已经在 8 月 16 日向 R 添加了缺少的功能。是的,当然是 R 的开发版本,也就是R-develR-devel另请参阅邮件列表 上的今天线程, https://stat.ethz.ch/pipermail/r-devel/2016-November/073378.html

于 2016-11-14T10:51:44.370 回答