Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Call Stack reporting in CATCH 1

Status
Not open for further replies.

wgcs

Programmer
Mar 31, 2002
2,056
EC
I'm trying to retrofit TRY..CATCH (VFP 9, now) into a program that has been around since VFP6...

One very frustrating thing is that if I put TRY...CATCH around my READ EVENTS (in an attempt to make errors recoverable, rather than choking out of the application) then I lose the Call Stack that existed when the exception was thrown.

(I know how to use TRY..CATCH on a closer scope, but the problem remains: If not EVERY routine has a TRY..CATCH in it, an one of those routines throws an error, then it's hard to report the application's status when the error occurs.

If instead, I use ON ERROR, then the error is not recoverable but I can report the actual call stack using a loop and PROGRAM(i) (Yeah, I know you can RETRY or RETURN instead of QUITing in the ON ERROR, but the offending Form doesn't disappear, and it just isn't as Clean as if the program jumped to the CATCH...)


Does anyone have an idea for how to report the offending callstack in a CATCH when the error occurred in a subroutine (Called from a subroutine, called from a subroutine, etc) called from the TRY block?

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
astackinfo reports the stack up to the routine containing the CATCH....

This is actually the second time I'm learning this... I had forgotten why I didn't try to put the TRY..CATCH right around the READ EVENTS before, but this page describes it well: (I am not the Tom or Kurt in the discussion, but I sympathize with their issues, which are exactly what I'm dealing with.)

Essentially, the problem is this (put this code in a file called testerr.prg, and answer Yes to the two messageboxes):
Code:
PROCEDURE TestErr
  ON ERROR do Oops with Program(), Message()
  DO Whoops  && This'll throw an error that can be analyzed

  TRY
    DO Whoops  && This'll throw an error that is very obscured
  CATCH TO oExc
    do Oops with Program(), Message(), oExc
  ENDTRY

  ON ERROR 

  modi file nowait TryCatchLog.txt
  modi file nowait OnErrorLog.txt
  
  messagebox('Now, compare the two logs that were generated to see how the stack info differs')
ENDPROC


procedure Oops( tcProg, tcMsg, toExc )
  LOCAL lnStackCnt, laStack[10]
  lnStackCnt = aStackInfo( laStack )

  if vartype(toExc)='O'
    * Called from Catch
    LIST MEMO TO TryCatchLog.txt
  else
    * called from ON-ERROR
    LIST MEMO TO OnErrorLog.txt
  endif

ENDPROC


procedure Whoops
  do Sub2
endproc

procedure Sub2
  do sub3
endproc

procedure Sub3
  if 6=MESSAGEBOX('Would you like to throw an error now?',4)
    ERROR 10  && throws syntax error
  endif
endproc


The callstacks (for anyone who doesn't feel like running the example) look like this:

For the TRY..CATCH error handler:
LNSTACKCNT Local N 2 ( 2.00000000) oops
LASTACK Local A oops
( 1, 1) N 1 ( 1.00000000)
( 1, 2) C "c:\source\lex\t\testerr.fxp"
( 1, 3) C "testerr"
( 1, 4) C "c:\source\lex\t\testerr.prg"
( 1, 5) N 8 ( 8.00000000)
( 1, 6) C " do Oops with Program(), Message(), oExc"
( 2, 1) N 2 ( 2.00000000)
( 2, 2) C "c:\source\lex\t\testerr.fxp"
( 2, 3) C "oops"
( 2, 4) C "c:\source\lex\t\testerr.prg"
( 2, 5) N 23 ( 23.00000000)
( 2, 6) C " lnStackCnt = aStackInfo( laStack )"



For the ON ERROR handler:
LNSTACKCNT Local N 5 ( 5.00000000) oops
LASTACK Local A oops
( 1, 1) N 1 ( 1.00000000)
( 1, 2) C "c:\source\lex\t\testerr.fxp"
( 1, 3) C "testerr"
( 1, 4) C "c:\source\lex\t\testerr.prg"
( 1, 5) N 3 ( 3.00000000)
( 1, 6) C "DO Whoops && This'll throw an error that can
be analyzed"
( 2, 1) N 2 ( 2.00000000)
( 2, 2) C "c:\source\lex\t\testerr.fxp"
( 2, 3) C "whoops"
( 2, 4) C "c:\source\lex\t\testerr.prg"
( 2, 5) N 37 ( 37.00000000)
( 2, 6) C " do Sub2"
( 3, 1) N 3 ( 3.00000000)
( 3, 2) C "c:\source\lex\t\testerr.fxp"
( 3, 3) C "sub2"
( 3, 4) C "c:\source\lex\t\testerr.prg"
( 3, 5) N 41 ( 41.00000000)
( 3, 6) C " do sub3"
( 4, 1) N 4 ( 4.00000000)
( 4, 2) C "c:\source\lex\t\testerr.fxp"
( 4, 3) C [red]"sub3"[/red]
( 4, 4) C "c:\source\lex\t\testerr.prg"
( 4, 5) N [red]46[/red] ( 46.00000000)
( 4, 6) C [red]" ERROR 10 && throws syntax error"[/red]
( 5, 1) N 5 ( 5.00000000)
( 5, 2) C "c:\source\lex\t\testerr.fxp"
( 5, 3) C "ON... "
( 5, 4) C "c:\source\lex\t\testerr.prg"
( 5, 5) N 23 ( 23.00000000)
( 5, 6) C " lnStackCnt = aStackInfo( laStack )"


Which one do you think is more useful for debugging?

The info in red in the second listing (from ON ERROR) points right to the line that threw the error... try figuring out anything close in the first listing (from the CATCH).

I think it is almost unconscionable that the FoxTeam gave us such powerful error handling in TRY..CATCH that can make code much more stable despite defects, and yet we have to give up hope of logging, finding and fixing the problems that are being caught!!!

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Bill,

I understand where you are coming from. However, Try...Catch...Finally is really a different ballgame. It indeed makes things more complex, and error handling/logging can't be had with just a single line of code (that's why I say I understand where you are coming from). But just for the sake of argument let's take a look at error escalation and what it can provide.

I've taken the liberty of modifying your example, and I certainly haven't put all the bells and whistles on this, but perhaps it still shows something that is useful and more powerful than the traditional On Error handler. Copy-n-paste the code below into a PRG and run it from within Visual FoxPro.
Code:
DO testerr

PROCEDURE testerr
	TRY
		DO Whoops  && This'll throw an error that is very obscured
	CATCH TO oExc
		oExc.COMMENT = [Perhaps Whoops caused this?]
		DO Oops WITH oExc, 0
	ENDTRY
	MODI FILE (ADDBS(SYS(2023)) + "TryCatchLog.txt") NOWAIT
ENDPROC


PROCEDURE Oops()
	LPARAMETERS toExc, tnLevel
	LOCAL lcErrorInfo, lcPadding
	lcPadding = REPLICATE(CHR(9), tnLevel)
	lcErrorInfo = lcPadding + [Exception Object ]  + TRANSFORM(tnLevel) + [:]+ CHR(13) + ;
		lcPadding + [  ErrorNo: ] + TRANSFORM(toExc.ERRORNO)  + CHR(13) + ;
		lcPadding + [  LineNo: ] + TRANSFORM(toExc.LINENO)   + CHR(13) + ;
		lcPadding + [  Message: ] + toExc.MESSAGE   + CHR(13) + ;
		lcPadding + [  Procedure: ] + toExc.PROCEDURE   + CHR(13) + ;
		lcPadding + [  Details: ] + toExc.DETAILS   + CHR(13) + ;
		lcPadding + [  StackLevel: ] + TRANSFORM(toExc.STACKLEVEL)   + CHR(13) + ;
		lcPadding + [  LineContents: ] + toExc.LINECONTENTS   + CHR(13) + ;
		lcPadding + [  Comments: ] + toExc.COMMENT   + CHR(13) + CHR(13)
	=STRTOFILE(lcErrorInfo, ADDBS(SYS(2023)) + "TryCatchLog.txt", 1)
	IF TYPE("toExc.UserValue") = "O"
		DO Oops WITH toExc.USERVALUE, tnLevel + 1
	ENDIF
ENDPROC

PROCEDURE Whoops
	TRY
		DO Sub2
	CATCH TO oExc1
		oExc1.COMMENT = [Perhaps sub2 caused this?]
		THROW oExc1
	ENDTRY
ENDPROC

PROCEDURE Sub2
	TRY
		DO sub3
	CATCH TO oExc2
		oExc2.COMMENT = [Perhaps sub3 caused this?]
		THROW oExc2
	ENDTRY
ENDPROC

PROCEDURE sub3
	TRY
		IF 6=MESSAGEBOX('Would you like to throw an error now?',4)
			ERROR 10  && throws syntax error
		ENDIF
	CATCH TO oExc3
		oExc3.COMMENT = [The user decided to throw an exception.]
		THROW oExc3
	ENDTRY
ENDPROC

boyd.gif

SweetPotato Software Website
My Blog
 
Craig,

Now, that's kinda neat! I remember the wrapping of exceptions in a new exception when THROWn from inside a CATCH, and I used to consider it to be entirely a nuisance.

However, your recursive method of reporting on the error is very clever, and makes complete use of the available info. It certainly gets more complete reporting, showing the TRY-STACK, if not the CALL-STACK.

It hadn't occurred to me to escalate an exception that far.., that is, that THROWing it from within multiple CATCHes, resulting in such a stack of exception objects... and it hadn't occurred to me that reporting on it could be so easy.

Thanks again!

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top