首页 > 解决方案 > rmarkdown::render() 输出到标准输出

问题描述

当我在 RStudio 中本地render()创建*.Rmd文件时,该render()函数的输出显示在控制台中:

基本.Rmd文件:

---
title: "test"
output: html_document
---

```{r setup, include=FALSE}

sink("./output.txt", type = 'output')

knitr::opts_chunk$set(echo = TRUE)
```

## Summary

```{r cars}
summary(cars)
```

## Error

```{r}

dbGetQuery()

```

构建:

library(rmarkdown)

render('./test.rmd')

输出:

在此处输入图像描述

当我在本地创建报告并且我可以看到进度和抛出的错误(如果有)时,这非常棒。我需要在 stdout(或 stderr)中监视此输出,但我无法将此输出接收到该位置,因为knitr正在使用capture.inputwhich uses sink()(见第一条评论)。我什至尝试下沉到一个文件,但是虽然output.txt创建了文件,但该文件中没有任何记录。

这对我来说是个问题,因为我render()在 Docker 容器中使用,我无法将.RmdDocker 容器中文件的块输出发送到 stderr 或 stdout。我需要监视.Rmd文件内容器 R 代码中的块输出错误(以诊断连接数据库连接错误)并将这些块发送到 stdout 或 stderr 是唯一的方法(无需登录到容器,其中我的用例(即部署到 AWS)是不可能的)

我已经查看了knitr 块选项,似乎没有任何选项可以设置来强制块输出到文件或 stdout 或 stderr。

有什么方法可以将所有块输出写入render()函数内部的 stdout 或 stderr 吗?这个几年前的问题与我的相似(如果不相同),但接受的答案不适合我的用例

标签: rr-markdownknitr

解决方案


我会采取两种方法来解决这个问题 - 取决于你想要什么。

如果您想查看 stderr/stdout 输出,就像在控制台中一样,完成此操作的最简单方法是使用 shell 脚本来呈现您的文档,并将输出通过管道传输到文本。- 更小的包包含一个示例 shell 脚本render.r 它对此非常有用。安装后littler,并确保脚本在您的路径上可用,您可以运行:

render.r test.rmd > output.txt

或者

render.r test.rmd > output.txt 2>&1

在输出文件中包含 stderr。

但是,我发现此控制台输出通常不够详细,无法用于调试和故障排除。

因此,另一种选择是编辑 Rmd 文件以记录有关进度/错误的更多详细信息,并将记录器输出定向到外部文件。

这在云或 docker-container 计算环境的上下文中特别有用,因为可以将日志定向到允许实时日志记录和跨多个作业搜索日志的数据存储。就个人而言,我使用futile.logger包来执行此操作。

使用由futile.logger创建的记录器,这将按如下方式工作:

  1. 在您的 Rmd 文件或 Rmd 文件中的代码调用的函数中,将重要的错误和警告消息重定向到记录器。做到这一点的最佳方法是另一个问题的主题,根据我的经验,任务因任务而异。

    • 至少,这会导致在您的 Rmd 文件中插入一系列 R 命令,如下所示:
      library(futile.logger)
      flog.info('Querying data .. ')
      data <- tryCatch(dbGetQuery(...),
                       warning = function(war) {flog.warn(war)}, 
                       error = function(err) {flog.error(err)},
                       ...)
      
      可能编辑记录的消息以提供更多上下文。
    • 更彻底的解决方案将全局应用于代码块或文件。我没有在 Rmd 的上下文中亲自对此进行过测试,但它可能涉及使用withCallingHandlers或更改options(error = custom_logging_function).
  2. 在您的 R session中,在渲染 Rmd 之前,将记录器输出重定向到文件或您想要的目的地。

    • 这看起来像:
      library(futile.logger)
      flog.logger(name = 'ROOT', 
                  appender = appender.file('render.log'))
      rmarkdown::render('my_document.Rmd')
      
  3. 在呈现文档时,您将看到记录器输出打印到render.log文件中。

我会注意到,虽然我积极使用该futile.logger包,但该包现在已被弃用为它的新迭代,称为logger。我没有专门尝试过这种方法logger,但我怀疑如果不是更好的话,它也会同样有效。logger docs 的这篇关于迁移的小插图很好地描述了 logger 和 futile.logger 之间的区别。


推荐阅读