# HG changeset patch # User Claus Gittinger # Date 853359062 -3600 # Node ID 3c6300f27f74380245af3d6febd89018f3127418 # Parent 01ad5ffe0c9db7db1cd3e7d3be2e008e1211d072 example section; added useful emergencyHandler section diff -r 01ad5ffe0c9d -r 3c6300f27f74 Exception.st --- a/Exception.st Wed Jan 15 19:08:31 1997 +0100 +++ b/Exception.st Wed Jan 15 21:11:02 1997 +0100 @@ -112,6 +112,48 @@ [author:] Claus Gittinger " +! + +examples +" + Examples on Exception-raising & handling are found in the doc/coding + section (CodingExamples). + + The emergencyHandler stuff is very useful, to prevent endUser applications + from entering the debugger. + Some commonly used (useful) emergency handlers are provided in the + 'useful handlers' section; try them to learn more + (especially, the mailingHandler is fun). + + Define a handler: + [exBegin] + Exception emergencyHandler:(Exception abortingEmergencyHandler) + [exEnd] + + + try some exception (for demonstration, in some other process): + [exBegin] + [ + #(1 2 3) at:4 + ] fork. + [exEnd] + + cleanup: + [exBegin] + Exception emergencyHandler:nil + [exEnd] + + + A handler which dumps information to a file (watch the file 'errorTrace.stx'): + [exBegin] + Exception emergencyHandler:(Exception dumpingEmergencyHandler) + [exEnd] + + A handler which sends you mail: + [exBegin] + Exception emergencyHandler:(Exception mailingEmergencyHandler) + [exEnd] +" ! ! !Exception class methodsFor:'initialization'! @@ -163,28 +205,37 @@ !Exception class methodsFor:'defaults'! emergencyHandler - "return the handler used for unhandled exceptions" + "return the handler used for unhandled exceptions. + + If no EmergencyHandler has been set, a handler which enters the + debugger is returned. + The debugger is opened by asking the signal for a debug action, + this allows to provide other debuggers in specialized (subclass-instances) + of Signal (if that is ever needed)" " set it up, when called the first time " EmergencyHandler isNil ifTrue:[ - EmergencyHandler := [:ex | - " - sending it to the signal allows per-signal specific - debuggers to be implemented in the future - (for example, segv in primitive code could show things - on the C-level ..) - " - (ex signal) enterDebuggerWith:ex message:(ex errorString). - ] + EmergencyHandler := [:ex | + " + sending it to the signal allows per-signal specific + debuggers to be implemented in the future + (for example, segv in primitive code could show things + on the C-level ..) + " + (ex signal) enterDebuggerWith:ex message:(ex errorString). + ] ]. ^ EmergencyHandler + + "Modified: 15.1.1997 / 20:50:37 / cg" ! emergencyHandler:aOneArgBlock - "set the handler used for unhandled exceptions" + "set the handler used for unhandled exceptions. + The default (a nil-handler) leads to a debugger to be shown." EmergencyHandler := aOneArgBlock @@ -218,7 +269,214 @@ [:ex | Smalltalk exitWithCoreDump. ] " - "Modified: 7.1.1997 / 21:15:07 / cg" + "Modified: 15.1.1997 / 20:49:06 / cg" +! ! + +!Exception class methodsFor:'useful handlers'! + +abortingEmergencyHandler + "return a block (usable as an emergency handler), + which aborts after showing a warnBox. + This is useful for endUser applications" + + ^ [:ex | self warn:'Error: ' , ex errorString. + AbortSignal raise + ] + + "test with (try a few halts or CTRL-C's): + Exception emergencyHandler:(Exception abortingEmergencyHandler) + " + + "back with: + Exception emergencyHandler:(Exception notifyingEmergencyHandler) + Exception emergencyHandler:nil + " + + "Created: 15.1.1997 / 20:13:06 / cg" + "Modified: 15.1.1997 / 20:15:02 / cg" +! + +dumpingEmergencyHandler + "return a block (usable as an emergency handler), + which dumps the stackBacktrace to a trace file and + aborts after showing a warnBox. + This is useful, for endUser application, which are still being + debugged (i.e. the programmers may have a look at the traceFile + from time to time). + + Notice: + The code below is just an example; you may want to change the + name of the error-file in your application + (but please: copy the code; do not modify here)" + + ^ [:ex | + |str printedException| + + ex signal == Signal noHandlerSignal ifTrue:[ + printedException := ex parameter. + ] ifFalse:[ + printedException := ex + ]. + + "/ user interruption is handled specially: + "/ allow user to choose between proceeding or aborting + "/ but never dump that information to the file. + + printedException signal == Object userInterruptSignal ifTrue:[ + (self confirm:'abort current action ?') ifTrue:[ + AbortSignal raise + ]. + ex proceed + ]. + + "/ + "/ dump it to 'errorTrace.stx' + "/ + str := 'errorTrace.stx' asFilename appendingWriteStream. + + str nextPutLine:('******************************* ' + , AbsoluteTime now printString + , ' *******************************'). + str cr. + + str nextPutLine:('** Error: ' , printedException errorString). + str nextPutLine:('** Signal: ' , printedException signal printString). + str nextPutLine:('** Parameter: ' , printedException parameter printString). + str nextPutLine:('** Process: ' , Processor activeProcess printString). + str nextPutLine:('** Backtrace:'). + str cr. + + printedException suspendedContext fullPrintAllOn:str. + str cr. + str cr. + str close. + + self warn:printedException errorString. + AbortSignal raise + ] + + "test with (try a few halts or CTRL-C's): + Exception emergencyHandler:(Exception dumpingEmergencyHandler) + " + + "back with: + Exception emergencyHandler:(Exception notifyingEmergencyHandler) + Exception emergencyHandler:nil + " + + "Created: 15.1.1997 / 20:14:52 / cg" + "Modified: 15.1.1997 / 21:07:14 / cg" +! + +mailingEmergencyHandler + "return a block (usable as an emergency handler), + which shows a warnBox and optionally mails a stackBacktrace to a maintainer. + This is useful, for endUser application, which are still being + debugged (i.e. the programmers may have a look at the errors). + + Notice: the stuff here is a demonstration only; it should be modified + for your particular environment ... + ... but please: copy the code and modify there; + leave the stuff below as it is." + + ^ [:ex | + |str printedException doMail emergencyMailReceiver pipe| + + ex signal == Signal noHandlerSignal ifTrue:[ + printedException := ex parameter. + ] ifFalse:[ + printedException := ex + ]. + + "/ user interruption is handled specially: + "/ allow user to choose between proceeding or aborting + "/ but never dump that information to the file. + + printedException signal == Object userInterruptSignal ifTrue:[ + (self confirm:'abort current action ?') ifTrue:[ + AbortSignal raise + ]. + ex proceed + ]. + + "/ somehow get the name of the guy to receive the mail + "/ you have to implement that yourself. + + "/ emergencyMailReceiver := OneOfYourClass getEmergencyMailReceiver. + emergencyMailReceiver := OperatingSystem getLoginName. + + emergencyMailReceiver isNil ifTrue:[ + self warn:(printedException errorString + , '\\No mailing to service people possible.') withCRs. + doMail := false. + ] ifFalse:[ + doMail := self confirm:(printedException errorString + , '\\Mail error information to the service people (' + , emergencyMailReceiver , ') ?') withCRs + ]. + doMail ifTrue:[ + str := '' writeStream. + + str nextPutLine:('Error notification from ' + , OperatingSystem getLoginName + , '@' + , OperatingSystem getHostName). + str cr. + + str nextPutLine:('Time: ' , AbsoluteTime now printString). + str nextPutLine:('Error: ', printedException errorString). + str nextPutLine:('Signal: ', printedException signal printString). + str nextPutLine:('Parameter: ', printedException parameter printString). + str nextPutLine:('Process: ', Processor activeProcess printString). + str nextPutLine:'Backtrace:'. + str cr. + + printedException suspendedContext fullPrintAllOn:str. + str cr;cr. + + str close. + + pipe := PipeStream + writingTo:'mail ', emergencyMailReceiver. + pipe notNil ifTrue:[ + pipe nextPutLine:'Subject: automatic error report'. + pipe nextPutAll:str contents. + pipe cr. + pipe close. + ] + ]. + + AbortSignal raise + ] + + "test with (try a few halts or CTRL-C's): + Exception emergencyHandler:(Exception mailingEmergencyHandler) + " + + "back with: + Exception emergencyHandler:(Exception notifyingEmergencyHandler) + Exception emergencyHandler:nil + " + + "Created: 15.1.1997 / 20:14:52 / cg" + "Modified: 15.1.1997 / 21:10:28 / cg" +! + +notifyingEmergencyHandler + "return a block (usable as an emergency handler for exceptions), + which does errorNotification before going into the debugger." + + ^ [:ex | nil errorNotify:ex errorString from:ex suspendedContext ] + + "test with (try a few halts or CTRL-C's): + Exception emergencyHandler:(Exception notifyingEmergencyHandler) + " + + "back with: + Exception emergencyHandler:nil + " + + "Modified: 15.1.1997 / 20:15:12 / cg" ! ! !Exception methodsFor:'accessing'! @@ -607,6 +865,6 @@ !Exception class methodsFor:'documentation'! version - ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.43 1997-01-07 20:42:18 cg Exp $' + ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.44 1997-01-15 20:11:02 cg Exp $' ! ! Exception initialize!