Specifying the global R option for handling non-catastrophic errors worked for me, along with a customized workflow for retaining info about the error and examining this info after the failure. I am currently running R version 3.4.1.
Below, I've included a description of the workflow that worked for me, as well as some code I used to set the global error handling option in R.
As I have it configured, the error handling also creates an RData file containing all objects in working memory at the time of the error. This dump can be read back into R using load()
and then the various environments as they existed at the time of the error can be inspected interactively using debugger(errorDump)
.
I will note that I was able to get line numbers in the traceback()
output from any custom functions within the stack, but only if I used the keep.source=TRUE
option when calling source()
for any custom functions used in my script. Without this option, setting the global error handling option as below sent the full output of the traceback()
to an error log named error.log
, but line numbers were not available.
Here's the general steps I took in my workflow and how I was able to access the memory dump and error log after a non-interactive R failure.
I put the following at the top of the main script I was calling from the command line. This sets the global error handling option for the R session. My main script was called myMainScript.R
. The various lines in the code have comments after them describing what they do. Basically, with this option, when R encounters an error that triggers stop()
, it will create an RData (*.rda) dump file of working memory across all active environments in the directory ~/myUsername/directoryForDump
and will also write an error log named error.log
with some useful information to the same directory. You can modify this snippet to add other handling on error (e.g., add a timestamp to the dump file and error log filenames, etc.).
options(error = quote({
setwd('~/myUsername/directoryForDump'); # Set working directory where you want the dump to go, since dump.frames() doesn't seem to accept absolute file paths.
dump.frames("errorDump", to.file=TRUE, include.GlobalEnv=TRUE); # First dump to file; this dump is not accessible by the R session.
sink(file="error.log"); # Specify sink file to redirect all output.
dump.frames(); # Dump again to be able to retrieve error message and write to error log; this dump is accessible by the R session since not dumped to file.
cat(attr(last.dump,"error.message")); # Print error message to file, along with simplified stack trace.
cat('\nTraceback:');
cat('\n');
traceback(2); # Print full traceback of function calls with all parameters. The 2 passed to traceback omits the outermost two function calls.
sink();
q()}))
Make sure that from the main script and any subsequent function calls, anytime a function is sourced, the option keep.source=TRUE
is used. That is, to source a function, you would use source('~/path/to/myFunction.R', keep.source=TRUE)
. This is required for the traceback()
output to contain line numbers. It looks like you may also be able to set this option globally using options( keep.source=TRUE )
, but I have not tested this to see if it works. If you don't need line numbers, you can omit this option.
- From the terminal (outside R), call the main script in batch mode using
Rscript myMainScript.R
. This starts a new non-interactive R session and runs the script myMainScript.R
. The code snippet given in step 1 that has been placed at the top of myMainScript.R
sets the error handling option for the non-interactive R session.
- Encounter an error somewhere within the execution of
myMainScript.R
. This may be in the main script itself, or nested several functions deep. When the error is encountered, handling will be performed as specified in step 1, and the R session will terminate.
- An RData dump file named
errorDump.rda
and and error log named error.log
are created in the directory specified by '~/myUsername/directoryForDump'
in the global error handling option setting.
At your leisure, inspect error.log
to review information about the error, including the error message itself and the full stack trace leading to the error. Here's an example of the log that's generated on error; note the numbers after the #
character are the line numbers of the error at various points in the call stack:
Error in callNonExistFunc() : could not find function "callNonExistFunc"
Calls: test_multi_commodity_flow_cmd -> getExtendedConfigDF -> extendConfigDF
Traceback:
3: extendConfigDF(info_df, data_dir = user_dir, dlevel = dlevel) at test_multi_commodity_flow.R#304
2: getExtendedConfigDF(config_file_path, out_dir, dlevel) at test_multi_commodity_flow.R#352
1: test_multi_commodity_flow_cmd(config_file_path = config_file_path,
spot_file_path = spot_file_path, forward_file_path = forward_file_path,
data_dir = "../", user_dir = "Output", sim_type = "spot",
sim_scheme = "shape", sim_gran = "hourly", sim_adjust = "raw",
nsim = 5, start_date = "2017-07-01", end_date = "2017-12-31",
compute_averages = opt$compute_averages, compute_shapes = opt$compute_shapes,
overwrite = opt$overwrite, nmonths = opt$nmonths, forward_regime = opt$fregime,
ltfv_ratio = opt$ltfv_ratio, method = opt$method, dlevel = 0)
At your leisure, you may load errorDump.rda
into an interactive R session using load('~/path/to/errorDump.rda')
. Once loaded, call debugger(errorDump)
to browse all R objects in memory in any of the active environments. See the R help on debugger()
for more info.
This workflow is enormously helpful when running R in some type of production environment where you have non-interactive R sessions being initiated at the command line and you want information retained about unexpected errors. The ability to dump memory to a file you can use to inspect working memory at the time of the error, along with having the line numbers of the error in the call stack, facilitate speedy post-mortem debugging of what caused the error.