Sorry for the long answer but I wanted to summarize all knowledge and references in one answer!
Main issues to be solved
tryCatch
"unrolls" the call stack to the tryCatch
call so that traceback
and sys.calls
do no longer contain the full stack trace to identify the source code line that causes an error or warning.
tryCatch
aborts the execution if you catch a warning by passing a handler function for the warning
condition. If you just want to log a warning you cannot continue the execution as normal.
dump.frames
writes the evaluation environments (frames) of the stack trace to allow post-mortem debugging (= examining the variable values visible within each function call) but dump.frames
"forgets" to save the workspace too if you set the parameter to.file = TRUE
. Therefore important objects may be missing.
Find a simple logging framework since R does not support decent logging out of the box
Enrich the stack trace with the source code lines.
Solution concept
Use withCallingHandlers
instead of tryCatch
to get a full stack trace pointing to the source code line that throwed an error or warning.
Catch warnings only within withCallingHandlers
(not in tryCatch
) since it just calls the handler functions but does not change the program flow.
Surround withCallingHandlers
with tryCatch
to catch and handle errors as wanted.
Use dump.frames
with the parameter to.file = FALSE
to write the dump into global variable named last.dump
and save it into a file together with the global environment by calling save.image
.
Use a logging framework, e. g. the package futile.logger
.
R does track source code references when you set options(keep.source = TRUE)
. You can add this option to your .Rprofile
file or use a startup R script that sets this option and source
your actual R script then.
To enrich the stack trace with the tracked source code lines you can use the undocumented (but widely used) function limitedLabels
.
To filter out R internal function calls from stack trace you can remove all calls that have no source code line reference.
Implementation
Code template
Instead of using tryCatch
you should use this code snippet:
library(futile.logger)
tryCatch(
withCallingHandlers(<expression>,
error = function(e) {
call.stack <- sys.calls() # is like a traceback within "withCallingHandlers"
dump.frames()
save.image(file = "last.dump.rda")
flog.error(paste(e$message, limitedLabels(call.stack), sep = "\n"))
}
warning = <similar to error above>
}
error = <catch errors and recover as you would do it normally>
# warning = <...> # never do this here since it stops the normal execution like an error!
finally = <your clean-up code goes here>
}
Reusable implementation via a package (tryCatchLog
)
I have implemented a simple package with all the concepts mentioned above.
It provides a function tryCatchLog
using the futile.logger
package.
Usage:
library(tryCatchLog) # or source("R/tryCatchLog.R")
tryCatchLog(<expression>,
error = function(e) {
<your error handler>
})
You can find the free source code at github:
https://github.com/aryoda/tryCatchLog
You could also source
the tryCatchLog
function instead of using a full blown package.
Example (demo)
See the demo file that provides a lot of comments to explain how it works.
References
Other tryCatch
replacements
Other helpful links
http://adv-r.had.co.nz/Exceptions-Debugging.html
A Warning About warning() - avoid R's warning feature
In R, why does withCallingHandlers still stops execution?
How to continue function when error is thrown in withCallingHandlers in R
Can you make R print more detailed error messages?
How can I access the name of the function generating an error or warning?
How do I save warnings and errors as output from a function?
options(error=dump.frames) vs. options(error=utils::recover)
General suggestions for debugging in R
Suppress warnings using tryCatch in R
R Logging display name of the script
Background information about the "srcrefs" attribute (Duncan Murdoch)
get stack trace on tryCatch'ed error in R