0

I have some R code that looks like this:

###Set base path for onedrive folder
basepath<-sprintf('C:/Users/%s/OneDrive - Company/General/PowerBI New/', Sys.info()[["user"]])

cat('filepath0 0_Views')
#0_Views
filepath0<-paste0(basepath,'0_Views/Views pull_20230411.R')
RunScript2(filepath0)
#clear the environment except for the base path
rm(list=ls()[! ls() %in% c("basepath","RunScript2")])


cat('filepath2 #monthly accrual report')
#monthly accrual report 
filepath2<-paste0(basepath, 'ONC - OPS - Monthly Accrual Report/ONC- Ops- Monthly Accrual Report 20221007.R')
RunScript2(filepath2)
#clear the environment except for the base path
rm(list=ls()[! ls() %in% c("basepath","RunScript2")])


cat('filepath3 #protocol dashboard')
#protocol dashboard
filepath3<-paste0(basepath, 'ONC -OPS - Protocol Dashboard/ONC-Ops-Protocol Dashboard.R')
RunScript2(filepath3)
 #clear the environment except for the base path
rm(list=ls()[! ls() %in% c("basepath","RunScript2")])

Basically: it has a parent directory, and then in 9 little chunks of code (3 pictured) it'll run a different R file. It says Runscript2() instead of source() because I'm working on a trycatch function.

For the trycatch, I WANT to save the error output to one location, with a description of what the error was, and ideally which file failed.

Right now I have this:

outputFile <-file("output.txt")
RunScript2 <- function(x){
  tryCatch(
    {
      result = source(x) 
      return(result)
    },
    error=function(e) {
      message('An error occurred')
      writeLines(as.character(e), outputFile)
    },
    warning=function(w) {
      message('A warning occurred')
      writeLines(as.character(w), outputFile)
    }
  )
}


close(outputFile)

The problem is, right now the output.txt file is created and stored in random locations (depending on what filepath was recently used) and I'd love to always put it in one set location (lets say a new subfolder of the main path called "errors". The other problem is that while it will record what the error was, I cant tell if it happened in Views pull_20230411.R or ONC-Ops-Protocol Dashboard.R or.... And lastly if no error happened, and no file was ever created, then the close(outputfile) itself errors.

Could anyone help?

Update based on some comments/suggestions

I'd prefer not to use a new package if possible. Several users will run this and I'd rather not require installations.

Also, I noticed something when testing a suggested answer. Lets say there is a serious error in the second chunk of code, and then just a warning in the next chunk of code. The script right now will write the 'output.txt' with the first error, and then immediately write over it with the next warning.

I supposed there's two ways to solve this (either write both into the file, or write two files). Writing two files in this case would be preferable, with different names.

Joe Crozier
  • 944
  • 8
  • 20
  • Regarding the location of the "output.txt" file: you may want to take a look at the "here" package ( see: https://here.r-lib.org/ ) or simply explicitly specify your working directory via the `setwd()` function – br00t May 30 '23 at 14:40
  • I'd rather not use a new package because several users run this file from their own R's. I.e. it would require them all installing it. As far as the setwd(), would that interfere with each R script being in a different location? Or would I just use it right before the close(outputfile) – Joe Crozier May 30 '23 at 14:45
  • Do the files you source call `setwd()` to change the current working directory? Or can you at least provide some sort of minimal [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) that we can run ourselves to see what's going on? – MrFlick May 30 '23 at 14:45
  • No i meant right there in the code I had above. How I changed the filepath before sourcing the R files. If the setwd() was inside the 'runscript2' I imagine it would change the path I just set. But I imagine I could setwd right before the close – Joe Crozier May 30 '23 at 14:47
  • 1
    `setwd()` is not required here (nor would it help), and `here::here()` is unfortunately quite limited in where it works. `box::file()` would work, but *only* if you consistently use box modules, you cannot mix it with `source()`. There are no good solutions using only core R: this is an unfortunate deficiency in R. – Konrad Rudolph May 30 '23 at 14:48

1 Answers1

0

You can try something similar to this:


RunScript2 <- function(x){
  basepath <- sprintf('C:/Users/%s/OneDrive - Company/General/PowerBI New/', Sys.info()[[ 'user' ]])
  setwd(basepath) # approach 1: go back to the basepath each time
  # outputFile <- file(file.path(basepath, 'output.txt')) # approach 2: explicitly specify the full path to the output.txt file
  outputFile <- file('output.txt')
  tryCatch(
    {
      result = source(x) 
      return(result)
    },
    error = function(e) {
      message('An error occurred in source file ', x)
      writeLines(sprintf('%s: %s', x, as.character(e)), outputFile)
    },
    warning = function(w) {
      message('A warning occurred in source file ', x)
      writeLines(sprintf('%s: %s', x, as.character(w)), outputFile)
    }
  )
}
br00t
  • 1,440
  • 8
  • 10
  • 1
    Doing `setwd()` here has no benefit, and creates issues. Just create the full path to the output file; *especially* if you hard-code the full path anyway (i.e. use approach 2; but this doesn't seem to be what OP really wants). – Konrad Rudolph May 30 '23 at 14:52
  • This ALMOST works. (honestly works well enough i may accept it as answer soon, but will update the question with why it could use a little tweak) – Joe Crozier May 30 '23 at 15:22
  • In order to avoid clobbering log entries `outputFile <- file('output.txt', open = 'at')` so that the file is opened for *appending* in text mode. – br00t May 30 '23 at 20:07