1
votes

Background: I am creating a script that logs the console output of a markdown file. It is needed in order to track errors within scheduled reports that run frequently. In the end - in case there is an error appearing while rendering - the log.txt file is sent automatically to my mailbox in order to get informed about the error incl. attached the log.txt file.

Now to my question which is only related to the logging of console output: In script.R I define the commands that has to be executed and the logfile name for each of the commands. Then I run the loop that iterates over the .Rmd files. So each .Rmd is rendered and the console output is logged with help of sink(). However, turns out that as soon an error is occurring while rendering, the sinking process doesn't stop (despite sink(NULL)) and the loop doesn't continue with rendering and logging file2.Rmd. Is there a solution for this problem?

So far I was expecting it to be an environment related problem. But this doesn't seem to be the critical issue. Would appreciate some help here.

script.R

data <- data.frame(command = c("file1.Rmd", "file2.Rmd"),
                   log = c("file1Log.txt", "file2Log.txt"))

for (i in 1:nrow(data)) {
  command_i <- as.character(data[i, "command"])
  log_i <- as.character(data[i, "log"])
  
  renderMarkdown <- function() {
    
    con <- file(log_i,"w")
    sink(con, append=TRUE)
    sink(con, append=TRUE, type="message")
    
    rmarkdown::render(input = command_i,
                      output_format = "html_document",
                      output_file = sub(".Rmd", "", command_i),
                      output_dir = getwd())
    
    sink()
  }
  
  env <- new.env()
  assign("command", command_i, envir = env)
  assign("log", log_i, envir = env)
  
  sinkMarkdown <- function(renderMarkdown, env) {
    environment(renderMarkdown) <- env
    renderMarkdown()
  }
  
  sinkMarkdown(renderMarkdown, env)
}

file1.Rmd and file2.Rmd are the default Markdown files that you get after creating a new .Rmd file. In order to throw an error I inserted print(errorOnPurpose) which represents an object that doesn't exist.

file1.Rmd (equivalent to file2.Rmd)

---
title: "file1"
author: "user"
date: "10 8 2020"
output: html_document
---

#```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
#```

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

#```{r cars}
summary(cars)
print(errorOnPurpose)
#```

## Including Plots

You can also embed plots, for example:

#```{r pressure, echo=FALSE}
plot(pressure)
#```

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

1

1 Answers

0
votes

As you have mentioned correctly, diversions should be stopped (in correct order). This is not happening in your code: sink() is called once and stops only the output diversion (you may use sink.number(type = "message") to check if message diversions are open). You should also close the connection using close().

Use try() to prevent errors in the .rmd file from breaking the loop.

renderMarkdown <- function() {
    
    con <- file(log_i,"w")
    sink(con, append=TRUE)
    sink(con, append=TRUE, type="message")
    
    try(
    rmarkdown::render(input = command_i,
                      output_format = "html_document",
                      output_file = sub(".Rmd", "", command_i),
                      output_dir = getwd())
    )
    
    sink(type = "message")
    sink(type = "output")
    close(con)

  }