From hb at maths.lth.se  Wed Sep  7 19:14:37 2005
From: hb at maths.lth.se (Henrik Bengtsson)
Date: Wed, 07 Sep 2005 19:14:37 +0200
Subject: [Rd] Tracebacks with tryCatch() and withCallingHandlers()?
Message-ID: <431F1FFD.7080700@maths.lth.se>

When batch processing analysis, I use tryCatch() for failure handling 
and to prevent unwanted interrupts.  I write detailed progress to log 
file and conditions (warnings and errors) are written to the same log 
file immediately by using withCallingHandlers(..., condition=function(c) 
cat(c, file=logFile)).  However, I would also like to write the call 
stack to the log file to further simplify troubleshooting;  traceback() 
does unfortunately not work here. From ?traceback, we have

  "Errors which are caught _via_ 'try' or 'tryCatch' do not generate a 
traceback, so what is printed is the call sequence for the last uncaught 
error, and not necessarily the last error."

(and it seems to be case for withCallingHandlers() too).  Does anyone 
know of a workaround for this?   Is there a way to get the call stack 
within the condition handler?

Example:

foo <- function() stop("whoops");
pre <- function() foo();
bar <- function() pre();

yo <- function(fcn=tryCatch) {
   fcn(bar(),
     error = function(ex) {
       str(ex);
       traceback();   # I would like to access the call stack here!
     }
   )
   traceback();
}

Calling these gives:

 > rm(.Traceback)
 > yo()  # Using tryCatch()
List of 2
  $ message: chr "whoops"
  $ call   : language foo()
  - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
No traceback available
No traceback available
 > traceback()
No traceback available

The same, but now with withCallingHandlers(), which does not "prevent" 
the error from interrupting the code, gives similar results
 > rm(.Traceback)
 > yo(fcn=withCallingHandlers)
List of 2
  $ message: chr "whoops"
  $ call   : language foo()
  - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
No traceback available
Error in foo() : whoops
 > traceback()
5: stop("whoops")
4: foo()
3: bar()
2: fcn(bar(), error = function(ex) {
        str(ex)
        traceback()
    })
1: yo(fcn = withCallingHandlers)

Traceback() is available if the error is "let through".  I am also aware 
that the 'call' element of the condition object reports "foo()", (which 
is better than nothing).  However, I am missing information on the 
calling functions pre() and bar().

In addition to traceback(), I've also tried sys.calls(), sys.frames() 
and sys.status(), but none of these seems to "report" that the error 
occured inside foo(), instead you only get

$sys.calls
$sys.calls[[1]]
yo()

$sys.calls[[2]]
fcn(bar(), error = function(ex) {
     str(ex)
     traceback()
     print(sys.status())
     str(sys.calls())
     str(sys.frames())
})

$sys.calls[[3]]
tryCatchList(expr, classes, parentenv, handlers)

...

Am I looking for something that I can't get?  Would a solution be for R 
to internally record the call stack as soon as a condition occurs/is 
instanciated?

Thanks for enlightning me

Henrik



[Rd] Tracebacks with tryCatch() and withCallingHandlers()?
Henrik Bengtsson