1

I am attempting to write error messages for my script to a log file. It works when I do:

test <- file("error_file.log", open = "wt")
sink(test, type = "message")
try(data <- read.delim("genes2.txt",
                   header = TRUE,
                   as.is = TRUE))
sink(type = "message", append = TRUE)
close(test)

However, when I add an additional component to the script, it does not append both error messages. In this case both input files do not exist and should give a "no such file directory" for each file. Here is my attempt for both input files:

enter code heretest <- file("error_file.log", open = "wt")

sink(test, type = "message")

try(data <- read.delim("genes2.txt",
                       header = TRUE,
                       as.is = TRUE))

sink(type = "message", append = TRUE)
close(test)

test2 <- file("error_file.log", open = "wt")
sink(test2, type = "message")

try(variables <- read.delim("Book3.txt",
                            header = TRUE, 
                            as.is = TRUE,
                            check.names = FALSE,
                            text = TRUE,
                            na.strings = c("", NA)))

sink(type = "message", append = TRUE)
close(test2)

Thank you!

P.s. would it be possible to customize my own error messages for each try()?

  • Use `tryCatch` instead of `try` to catch and replace the error message, e. g.: `tryCatch(stop("stupid msg"), error = function(e) { if (grepl("stupid msg", e$message, fixed = TRUE)) print("clever msg") else print(e$message)})`. The risky part is that other R installations might emit error messages in different languages than English... – R Yoda Dec 20 '17 at 06:38
  • Could you perhaps give this example in the context of my script above. I am not sure where to place which function. Thank you! –  Dec 21 '17 at 07:12

2 Answers2

1

Try using this, it'll append both the messages to error_file.log:-

test <- file("error_file.log", open = "wt")
sink(test, append = TRUE, type = "message")


try(data <- read.delim("genes2.txt",
                       header = TRUE,
                       as.is = TRUE))


try(variables <- read.delim("Book3.txt",
                            header = TRUE, 
                            as.is = TRUE,
                            check.names = FALSE,
                            text = TRUE,
                            na.strings = c("", NA)))


sink(type = "message")

So, error file would have:-

Error in file(file, "rt") : cannot open the connection
In addition: Warning message:
In file(file, "rt") :
  cannot open file 'genes2.txt': No such file or directory
Error in file(file, "rt") : cannot open the connection
In addition: Warning message:
In file(file, "rt") :
  cannot open file 'Book3.txt': No such file or directory

I hope this solves your problem.

The trick is just open your log file and sink once in the begining. And, close sink in the end.

sm925
  • 2,648
  • 1
  • 16
  • 28
  • Strange, when I tried that approach it did not work, now it does. Welcome to programming I guess. Do you have an idea for custom messages? –  Dec 18 '17 at 16:03
  • Please accept answer if it solved your problem. Custom messages as in? – sm925 Dec 18 '17 at 16:04
  • Sorry about that. Instead of the whole: In file(file, "rt") : cannot open file 'Book3.txt': No such file or directory. I would make the error something like: "Please check your input file". into the error_file.log. –  Dec 18 '17 at 16:07
  • If I understand it correctly, you would need `gsub` to customize your messages. – sm925 Dec 18 '17 at 16:14
0

Using the valid answer of @suchait as basis you can customize your error message this way:

test <- file("error_file.log", open = "wt")
sink(test, append = TRUE, type = "message")

tryCatch(data <- read.delim("genes2.txt", header = TRUE, as.is = TRUE),
         error = function(e) {
           # replace one specific error message with another one
           if (grepl("cannot open", e$message, fixed = TRUE))
             # using "message" instead of "print" since you are sinking into type "message" (not "output")
             message("Customized error message 1: The file could not be opened\n")
           else
             message(e$message)
         }
         # If you wanted to replace the warnings too you will run into big problems:
         # tryCatch stops the execution and the error handler above is never called
         # causing the log to be empty. Conclusion: Don't reinvent the wheel and
         # use a suitable logging framework (e. g. the package "futile.logger")...
         # , warning = function(w) {return("Warning ignored...")}  # ignore warnings
)

tryCatch(variables <- read.delim("Book3.txt", header = TRUE, as.is = TRUE, check.names = FALSE, text = TRUE, na.strings = c("", NA)),
         error = function(e) {
           # Always write your specific error message (+ the original message if you want)
           message(paste("Customized error message 2: The file could not be opened. Details:", e$message, "\n"))
         }
)

sink(type = "message")

If you wanted to replace the warnings too you will run into problems (see my comments in the code above) and the solution would be an even more complicated code (using withCallingHandlers + try)

Therefore I think it is better to use an existing logging framework like the package futile.logger (see function ftry) instead of reinventing the wheel and running into many problems. You can set the "severity level" then to log e. g. only errors but no warnings...

tryCatch is a beast in R if you want to combine error handling with logging (see R: Catch errors and continue execution after logging the stacktrace (no traceback available with tryCatch) for details and a long list of related SO questions)...

If you want to add automatic logging to try and tryCatch you could use the package tryCatchLog (https://github.com/aryoda/tryCatchLog). For compliance reasons: I am the author of the package...

R Yoda
  • 8,358
  • 2
  • 50
  • 87