Normally you do not expect an application user to debug it, so you never want your delivered application to call the debugger. Obviously you try to achieve that by making the application error-free, but it is difficult to guarantee that the application never calls error. You therefore handle errors in the application, such that even if an error occurs it does not enter the debugger.
Error handling can be dynamically-scoped or global.
Dynamically-scoped error handling is done by wrapping
cl:handler-bind
or
cl:handler-case
around a body of code. This has the advantage that it allows you to tailor the response to errors in specific pieces of code and for specific types of error. It has the disadvantage that it is not global. If you put it in the process function (the function argument to
mp:process-run-function
) it will apply only to the code that is executed in that process, but you still need it in each process.
The global error handling is done by setting
cl:*debugger-hook*
. This applies to anything that tries to enter the debugger, in particular any
cl:error
call that was not handled otherwise. It has the advantage that it really is global, but the disadvantage that it cannot be tailored locally.
Since the
cl:*debugger-hook*
is applied only if the error was not handled, the two mechanisms can be used at the same time and typically they are. The dynamically-scoped ones are used to give the accurate response, while the global one used to catch any error that is not handled for some reason.
In either case, the handling means that some of your code is being executed. Either it is the function is bound to the error type in
cl:handler-bind
or set to
cl:*debugger-hook*
, or the body in the clause in
cl:handler-case
. This code should the "right thing" to deal with the situation. For unexpected errors, that normally would mean generating some log of the problem, telling the end-user that something went wrong, maybe giving the user some options of actions, and aborting (note that
cl:handler-case
already aborted when the code is executed).
The log of the problem would normally be a bug form , which you can generate by
(dbg:output-backtrace :bug-form ...)
If you can obtain the bug form, it will give you (the programmer) a chance to identify the reason for the error. There is also
dbg:log-bug-form
which writes it to a file. You would not normally show the bug form to the end-user. Instead, in a GUI application you will probably want to display a dialog informing the user that something went wrong and maybe giving them some options. In a console application you probably want to just print a short message.
There is a simple example of using
cl:*debugger-hook*
in
(sys:example-file "delivery/debugger-hook/")
LispWorks Delivery User Guide - 13 Dec 2011