I want to know if there is the possibility to create a log with the information of the "error" that force the tryCatch to do "error handling"?
Is to be able to gain visibility of potential errors. I want to avoid doing prints.
Thanks!
this will work:
outputFile <-file("output.txt")
tryCatch({
--- your code ---
}, error = function(e) {
writeLines(as.character(e), outputFile)
})
-----------------------------
close(outputFile)
Related
I have code that includes several initial checks of different parameter values. The code is part of a larger project involving several R scripts as well as calls from other environments. If a parameter value does not pass one of the checks, I want to
Generate a customizable result code
Skip the remaining code (which is not going to work anyhow if the parameters are wrong)
Create a log entry with the line where the error was thrown (which tells me which test was not passed by the parameters)
Print my customizable result code to the console (without a more detailed explanation / trace back from the error)
Otherwise, the remaining code should be run. If there are other errors (not thrown by me), I also need an error handling resulting in a customizable general result code (signalling that there was an error, but that it was not one thrown by me) and a more detailled log.
The result codes are part of the communication with a larger environment and just distinguishes between wrong parameter values (i.e., errors thrown by me) and other internal problems (that might occur later in the script).
I would like to use tryCatchLog because it allows me to log a detailed traceback including the script name (I am sourcing my own code) and the line number. I have not figured out, however, how to generate my own error code (currently I am doing this via the base function stop()) and pass this along using tryCatchLog (while also writing a log).
Example
In the following example, my parameter_check() throws an error via stop() with my result code "400". Using tryCatchLog I can catch the error and get a detailed error message including a traceback. However, I want to seperate my own error code (just "400"), which should be printed to the console, and a more detailed error message, which should go to a log file.
library(tryCatchLog)
parameter_check <- function(error) {
if (error){
stop("400")
print("This line should not appear")
}
}
print("Beginning")
tryCatchLog(parameter_check(error = TRUE),
error = function(e) {print(e)}
)
print("End")
Currently, the result is:
[1] "Beginn"
ERROR [2021-12-08 11:43:38] 400
Compact call stack:
1 tryCatchLog(parameter_check(0), error = function(e) {
2 #3: stop("400")
Full call stack:
1 tryCatchLog(parameter_check(0), error = function(e) {
print(e)
2 tryCatch(withCallingHandlers(expr, condition =
cond.handler), ..., finall
3 tryCatchList(expr, classes, parentenv, handlers)
4 tryCatchOne(expr, names, parentenv, handlers[[1]])
5 doTryCatch(return(expr), name, parentenv, handler)
6 withCallingHandlers(expr, condition = cond.handler)
7 parameter_check(0)
8 #3: stop("400")
9 .handleSimpleError(function (c)
{
if (inherits(c, "condition")
<simpleError in parameter_check(0): 400>
I would like to get my own result code ("400") so that I can print it to the console while logging the complete error message in a file. Is there a way of doing it without writing code parsing the error message, etc.?
Solution with tryCatch
Based on the hint by R Yoda and this answers this is a solution with tryCatch and calling handlers.
### Parameters
log_file_location <- "./logs/log.txt"
### Defining functions
parameter_check_1 <- function(error) {
if (error){
stop("400")
}
}
parameter_check_2 <- function(error) {
if (error){
stop("400")
}
}
write_to_log <- function(file_location, message) {
if (file.exists(file_location))
{write(message, file_location, append = TRUE)}
else
{write(message, file_location, append = FALSE)}
}
parameter_check <- function(){
print("Beginning of parameter check")
print("First check")
parameter_check_1(error = TRUE)
print("Second check")
parameter_check_2(error = FALSE)
print("End of parameter check")
}
main<- function() {
print("Beginning of main function")
log(-1) # throws warning
log("error") # throws error
print("End of main function")
}
### Setting parameters
result_code_no_error <- "200"
result_code_bad_request <- "400"
result_code_internal_error <- "500"
# initial value for result_code
result_code <- result_code_no_error
print("Beginning of program")
### Execute parameter check with tryCatch and calling handlers
# Error in parameter checking functions should result in result_code_bad_request
tryCatch(withCallingHandlers(parameter_check(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_bad_request
}
)
### Execute main section with tryCatch and calling handlers
# Error in main section should result in result_code_internal_error
# main section should only be excecuted if there is no error (internal or bad request) in the previous section
if (result_code == result_code_no_error) {
tryCatch(withCallingHandlers(main(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_internal_error
}
)
}
print("End of program")
print(result_code)
As explained in the vignette for tryCatchLog this has the disadvantage of not logging the precise location of the error. I am not passing on the error message from stop("400"), because all parameter checking functions are in one function call now, but this could be done using condition$message.
The solution is (totally independent of using tryCatchLog or standard R tryCatch):
...
error = function(e) {print(e$message)}
..
Background (how R errors work): They create an object of type (error) condition:
e <- simpleError("400") # same "condition" object as created by stop("400")
str(e)
# List of 2
# $ message: chr "400"
# $ call : NULL
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
print(e$message)
[1] "400"
I want to write a error log for one of my functions (see below). However, when the function fails, the sink won't get closed properly. Is there a way to always close the sinks() upon exiting the function?
some_function <- function(){
con <- file("test.log")
sink(con, append=TRUE,type="output",split=TRUE)
sink(con, append=TRUE,type="message")
>> do some stuff that may fail.
sink()
sink(type = "message")
}
Use try.
try(lm(1), outFile="error.txt") ## failing stuff
File contains:
Error in formula.default(object, env = baseenv()) : invalid formula
I am a beginner in R,
While I have to edit some pre written codes in R.
there is a specific one which I cannot understand.
it would be really helpful if anyone can help me understand this.
# Logger
log.msg = function(msg){
## capture messages and errors to a file.
fileConn<-file("output.txt", open = "a+")
writeLines(c(msg), fileConn)
close(fileConn)
}
log.msg("Start Data extraction and merging..")
log.msg = function(msg){
## capture messages and errors to a file.
## create file connection in append mode (a+)
fileConn<-file("output.txt", open = "a+")
## write the msg to this file
writeLines(c(msg), fileConn)
## close connection
close(fileConn)
}
When I run this code in the R console, it works fine:
read.csv('https://courses.edx.org/c4x/MITx/15.071x_2/asset/WHO.csv')
But when I try to put in into an R markdown document and knit it, I get the following:
Error in open.connection(file, "rt") : cannot open the connection
Calls: <Anonymous> ... eval -> read.csv -> read.table -> open -> open.connection
Execution halted
I also tried using http and url(), but neither helped
read.csv('http://courses.edx.org/c4x/MITx/15.071x_2/asset/WHO.csv')
read.csv(url('http://courses.edx.org/c4x/MITx/15.071x_2/asset/WHO.csv'))
Both work fine in usual R sessions.
How can knitr? I hope there are ways that avoid downloading the file and placing it somewhere into working directory.
For linking purposes: It's the same issue as in read.table() and read.csv both Error in Rmd, but it my case I'm trying to read from an url, not from a file.
Thus adapting #Thomas's answer to your data, the following does the trick.
library(RCurl)
data <- getURL("https://courses.edx.org/c4x/MITx/15.071x_2/asset/WHO.csv",
ssl.verifypeer=0L, followlocation=1L)
read.csv(text=data)
You may also check Error when knitr has to download a zip file, where dropping https for http helped.
Answer of #puslet88 helped, but I modified it slightly to be less "intrusive".
So what I did was putting the following at the beginning of the Rmd fine:
```{r, echo=FALSE, warning=FALSE, message=FALSE}
library(RCurl)
read.csv.orig = read.csv
read.csv = function(file, ...) {
if (is.character(file)) {
if (grepl('^https://', file)) {
data = getURL(file, ssl.verifypeer=0L, followlocation=1L)
return (read.csv.orig(text=data, ...))
} else if (grepl('^http://', file)) {
data = getURL(file)
return (read.csv.orig(text=data, ...))
} else {
return (read.csv.orig(file, ...))
}
} else {
return (read.csv.orig(file, ...))
}
}
```
Now I don't have to change all the calls to read.csv in my R markdown document, I use it as before:
read.csv('https://courses.edx.org/c4x/MITx/15.071x_2/asset/WHO.csv')
I heard about exception handling first time in python two days ago and consequently I want to apply here in R. I had a look at a number of questions post either here in stack overflow or some other online Q&As but I am still really confused in using it.
I would really appreciate if someone can answer it with this simple example so later on I can apply it to my questions.
For example I have 3 data files with file names shown below; and the first file is a 0 bytes empty file. What I can do to continue run the loop for all files and the number extracted from the empty file can be expressed as NA?
> output_names_hdf5_list[1:5]
[1] "simulation-results fL=0.1,fks=1,fno=0.1,fnc=0.1,fr=0.1,fs=0.1.hdf5"
[2] "simulation-results fL=0.1,fks=1,fno=0.1,fnc=0.1,fr=0.1,fs=1.05.hdf5"
[3] "simulation-results fL=0.1,fks=1,fno=0.1,fnc=0.1,fr=0.1,fs=2.hdf5"
for (i in 1:5){
channelflow_outlet[,i]=h5read(paste(outputdir, output_names_hdf5_list[i], sep=""),"Channel")$Qc_out[460,][2:100]
}
With try function I can manage to run the program without stuck in an error message but when I replace the argunment with channelflow_outlet[,i]= h5read(....) inside try function, it just returns error.
for (i in 1:5){
try(h5read(paste(outputdir, output_names_hdf5_list[i], sep=""),"Channel")$Qc_out[460,][2:100])
}
Without error handling, it will have a error message like this.
> h5read(paste(outputdir, output_names_hdf5_list[1], sep=""),"Channel")$Qc_out[460,][2:100]
HDF5: unable to open file
Error in h5checktypeOrOpenLoc(file, readonly = TRUE) :
Error in h5checktypeOrOpenLoc(). File 'D:/Data/Mleonard/pytopkapi.staged.makefile/RunModel/Output/3x6-729-04072014/simulation-results fL=0.1,fks=1,fno=0.1,fnc=0.1,fr=0.1,fs=0.1.hdf5' is not a valid HDF5 file.
>
I hope my code helps. For those messages in the code, you can delete them if you want. They are here purely to help you see where it shows warning or error.
setwd("D:/Dropbox/Test/"); outputdir = "D:/Dropbox/Test/"
output_names_hdf5_list=c("simulation-results fL=0.1,fks=1,fno=1.05,fnc=1.05,fr=1.05,fs=1.05.hdf5",
"simulation-results fL=0.1,fks=1,fno=1.05,fnc=2,fr=1.05,fs=1.05.hdf5",
"simulation-results fL=0.1,fks=1,fno=2,fnc=1.05,fr=0.1,fs=1.05.hdf5",
"simulation-results fL=0.1,fks=1,fno=2,fnc=1.05,fr=2,fs=2.hdf5",
"simulation-results fL=0.5,fks=1,fno=2,fnc=2,fr=0.1,fs=1.05.hdf5")
channelflow_outlet = matrix(NA, nrow=100, ncol=5)
hdf5_list_reading_tool= function(output_names_hdf5_list) {
out = tryCatch(
{
message("This is the 'try' part")
h5read(paste(outputdir, output_names_hdf5_list, sep=""),"Channel")$Qc_out[460,][2:100]
},
error=function(cond) {
message("Here's the original error message:")
message(cond)
return(rep(NA,100))
},
warning=function(cond) {
message("Here's the original warning message:")
message(cond)
return(rep(NA,100))
},
finally={
message(paste("Processed URL:", output_names_hdf5_list))
message("Some other message at the end")
}
)
return(out)
}
channelflow_outlet=sapply(output_names_hdf5_list, hdf5_list_reading_tool)