From thomas.friedrichsmeier at ruhr-uni-bochum.de  Mon Oct 10 16:55:46 2005
From: thomas.friedrichsmeier at ruhr-uni-bochum.de (Thomas Friedrichsmeier)
Date: Mon, 10 Oct 2005 16:55:46 +0200
Subject: [Rd] Catching warning and error output
Message-ID: <200510101655.46264.thomas.friedrichsmeier@ruhr-uni-bochum.de>

Hi all,

I'm working on a GUI frontend for R, and I'm looking for a good way to catch 
all warning- and error-output. The reason for this is mostly, that I would 
like to know, which sections of the output are "normal" output, warnings, and 
errors. This would allow for some nice features, such as highlighting 
warnings and errors in a different color, or popping up a message like e.g. 
"There were these warnings, while doing this-or-that:".
Maybe a good solution for this already exists, but I have not been able to 
find it. Therefore, I'll outline what I have tried/considered so far, and 
what I think might be ways to add a corresonding API. Of course, I'm not very 
familiar with R, so these suggestions are probably not "the right way to do 
it".

What I've tried so far:
1) Directing stderr-output to a file (using sink ()):
This solution splits warnings, and errors from "regular" output. Using
options (error=quote (myhandler ())
I can additionally tell warnings and errors apart after the fact. However, 
this solution is problematic, in that then the output is handled 
asynchronously, and I can not tell, at which position in the output a warning 
should have been printed. Further, if the user runs one "sink ()" too many 
(the user has a sort of console for direct interaction with R), the 
output-handling will be broken in my GUI.

2) Use options (warning.expression=...), and options (error=...):
Unfortunately, it turned out, that when setting warning.expression to 
something non-NULL, the warning is discarded completely. There is no way to 
get at the warning that would have been generated.

3) Use condition handlers:
3a) Wrap each call inside withCallingHandlers (...):
This would probably work, but add quite a bit of overhead for string 
manipulation, and parsing. The GUI runs a lot of small commands during normal 
operation. There are additional hazzles, such as error messages would then 
all look like "Error in withCallingHandlers(...", and I'd have to use yet 
more string operations to make them look normal.
Also: Can I be sure, that all warnings (i.e. even from C-code) are signalled 
as conditions? I'm afraid I do not fully understand the internal going-ons, 
here.
If all else fails, I'll have to use this, but I'm not very happy with this.
3b) Use ".Internal (.addCondHands (...))" once to set up persistent handlers:
This worked fine, when testing it in the R-console. However, in my GUI, calls 
are actually handled using R_tryEval (..., R_GlobalEnv, ...). It seems the 
condition handlers do not carry over between two successive calls of 
R_tryEval. So effectively, I'd once again be back at 3a.

What I would like to have:
Of course there would be many different ways to accomplish this. Here are some 
solutions I can think of:

1) In my programmers' dream, there'd simply be three callbacks that I can 
override: R_WriteConsole (exists), R_WriteWarning, and R_WriteError. 
R_WriteWarning, and R_WriteError would be called from vwarningcall_dflt, and 
verrorcall_dflt, respectively, instead of REprintf. The default 
implementation of those, would of course simply call REprintf. Drawbacks: 
a) REprintf is available for use in R_ext/Print.h. I'd miss out on any direct 
calls of REprintf, while those should probably still be recorded as a 
warning/error.
b) I'd have to add a fairly elaborate implementation in order to honor any 
sinks the user has (purposefully) created. If I can even access all necessary 
data/functions from my code (I have not investigated that, yet).

2) Similar, but add the hook a little later, in REvprintf. There, instead of 
directly calling R_WriteConsole, a new callback R_WriteError would be used 
(which defaults to R_WriteConsole). Using this callback I would get a stream 
of both warnings, and errors, separate from "regular" output. I could tell 
warnings and errors apart, using options (error=...).

3) Yet a little less intrusive: Somehow use a fake R_ErrorCon:
There I'd simply add my own callback for con->vprintf, and con->fflush. Then 
proceed as in 2. However, it seems Rconnection and the related functions are 
too tightly guarded against this approach. I simply don't see a way, how I 
could fake this connection (but maybe there is one?). Maybe a public API 
could be added to allow this.

Ok, so much on my helpless attempts. Could you help me with this?

Thanks!
Thomas



[Rd] Catching warning and error output
Thomas Friedrichsmeier