过去,在以非交互方式渲染 R Markdown 时可以获得信息丰富的回溯,回溯只会显示 R Markdown 笔记本中代码的函数调用,只要笔记本包含此代码(在 Advanced R 2nd 中建议)版本):
options(rlang_trace_top_env = rlang::current_env())
options(error = function() {
sink()
print(rlang::trace_back(bottom = sys.frame(-1)), simplify = "none")
})
但是,这种行为似乎在 R、knitr、rmarkdown 和 rlang 的新版本中消失了,相反,回溯包含大量 knit 和 rmarkdown 函数调用,但 R Markdown 源文件本身没有任何内容。
这是一个简单的
notebook.Rmd
,它使用上面的代码并抛出错误:
---
title: "example notebook"
output:
html_document
params:
to_error: true
---
```{r setup}
options(rlang_trace_top_env = rlang::current_env())
options(error = function() {
sink()
print(rlang::trace_back(bottom = sys.frame(-1)), simplify = "none")
})
knitr::opts_chunk$set(message = FALSE)
```
```{r error}
throw_error <- function(to_error) {
func(to_error)
}
func <- function(to_error) {
if (to_error) stop('ERROR')
}
message(paste("to_error:", params$to_error, "(", class(params$to_error), ")"))
throw_error(params$to_error)
```
从终端渲染:
R -e "rmarkdown::render('notebook.Rmd')"
其中全局错误选项是
NULL
:
getOption('error')
空
旧版本:
输出很有帮助,仅在回溯中显示 R Markdown 文件中的代码:
processing file: notebook.Rmd
|.................. | 25%
ordinary text without R code
|................................... | 50%
label: setup
|.................................................... | 75%
ordinary text without R code
|......................................................................| 100%
label: error
to_error: TRUE ( logical )
Quitting from lines 19-27 (notebook.Rmd)
Error in func(to_error) : ERROR
Calls: <Anonymous> ... withCallingHandlers -> withVisible -> eval -> eval -> throw_error -> func
█
1. └─global::throw_error(params$to_error)
2. └─global::func(to_error)
3. └─base::stop("ERROR")
Warning message:
In sink() : no sink to remove
但是对于新版本:
输出非常详细,包括堆栈中的 rmarkdown 和 knit 调用,但最重要的是不包括 R Markdown 文件中的底层代码。
processing file: notebook.Rmd
|..............................................................| 100% [error]Error in `func()`:
! ERROR
Backtrace:
1. rmarkdown::render("notebook.Rmd")
2. knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
3. knitr:::process_file(text, output)
6. knitr:::process_group(group)
7. knitr:::call_block(x)
...
14. base::withRestarts(...)
15. base (local) withRestartList(expr, restarts)
16. base (local) withOneRestart(withRestartList(expr, restarts[-nr]), restarts[[nr]])
17. base (local) docall(restart$handler, restartArgs)
19. evaluate (local) fun(base::quote(`<smplErrr>`))
▆
1. ├─rmarkdown::render("notebook.Rmd")
2. │ └─knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
3. │ └─knitr:::process_file(text, output)
4. │ ├─xfun:::handle_error(...)
5. │ ├─base::withCallingHandlers(...)
6. │ └─knitr:::process_group(group)
7. │ └─knitr:::call_block(x)
8. │ └─knitr:::block_exec(params)
9. │ └─knitr:::eng_r(options)
10. │ ├─knitr:::in_input_dir(...)
11. │ │ └─knitr:::in_dir(input_dir(), expr)
12. │ └─knitr (local) evaluate(...)
13. │ └─evaluate::evaluate(...)
14. │ └─base::withRestarts(...)
15. │ └─base (local) withRestartList(expr, restarts)
16. │ └─base (local) withOneRestart(withRestartList(expr, restarts[-nr]), restarts[[nr]])
17. │ └─base (local) docall(restart$handler, restartArgs)
18. │ ├─base::do.call("fun", lapply(args, enquote))
19. │ └─evaluate (local) fun(base::quote(`<smplErrr>`))
20. │ └─base::signalCondition(cnd)
21. └─knitr (local) `<fn>`(`<smplErrr>`)
22. └─rlang::entrace(e)
23. └─rlang::cnd_signal(entraced)
24. └─rlang:::signal_abort(cnd)
25. └─base::stop(fallback)
Quitting from lines 19-27 [error] (notebook.Rmd)
这些较新的软件包版本中的一个或某些是否出现了退化?或者我忽略了 R 环境的一些内容? 如何获得仅显示 R Markdown 文件中的代码,但使用这些较新版本的 R、rmarkdown、knitr 和 rlang 的回溯?
编辑:我使用 conda 在两个不同的环境之间切换,并使用上面列出的 R 和软件包版本集。我能够在 macOS 和 Linux 上重现这一点。
事实证明这是评估包中的一个错误。自 evaluate v1.0.2.
起已修复此外,Pos 开发者计划发布一个新的 rlang 补丁版本,它将产生所需的回溯树,而无需设置任何选项(参见拉取请求)。
processing file: notebook.Rmd
|..............................................................| 100% [error]Error in `func()`:
! ERROR
Backtrace:
1. global throw_error(params$to_error)
2. global func(to_error)
▆
1. ├─global throw_error(params$to_error)
2. │ └─global func(to_error)
3. │ └─base::stop("ERROR")
4. └─base::.handleSimpleError(`<fn>`, "ERROR", base::quote(func(to_error)))
5. └─knitr (local) h(simpleError(msg, call))
6. └─rlang::entrace(e)
7. └─rlang::cnd_signal(entraced)
8. └─rlang:::signal_abort(cnd)
9. └─base::stop(fallback)
Quitting from lines 19-27 [error] (notebook.Rmd)