Next: Other Uses for Conditions, Previous: Restarts, Up: Common Lisp Conditions [Contents][Index]
Since restarts must be explicitly invoked to have any effect, you can define
multiple restarts, each providing a different recovery strategy. Not all
log-parsing applications will necessarily want to skip malformed entries. Some
applications might want parse-log-file
to include a special kind of object
representing malformed entries in the list of log-entry objects; other
applications may have some way to repair a malformed entry and may want a way
to pass the fixed entry back to parse-log-entry
.
To allow more complex recovery protocols, restarts can take arbitrary
arguments, which are passed in the call to INVOKE-RESTART
. You can provide
support for both the recovery strategies I just mentioned by adding two
restarts to parse-log-entry
, each of which takes a single argument. One
simply returns the value it’s passed as the return value of parse-log-entry
,
while the other tries to parse its argument in the place of the original log
entry.
(defun parse-log-entry (text) (if (well-formed-log-entry-p text) (make-instance 'log-entry ...) (restart-case (error 'malformed-log-entry-error :text text) (use-value (value) value) (reparse-entry (fixed-text) (parse-log-entry fixed-text)))))
The name USE-VALUE
is a standard name for this kind of restart. Common Lisp
defines a restart function for USE-VALUE
similar to the skip-log-entry
function you just defined. So, if you wanted to change the policy on malformed
entries to one that created an instance of malformed-log-entry
, you could
change log-analyzer
to this (assuming the existence of a
malformed-log-entry
class with a ‘:text’ initarg):
(defun log-analyzer () (handler-bind ((malformed-log-entry-error #'(lambda (c) (use-value (make-instance 'malformed-log-entry :text (text c)))))) (dolist (log (find-all-logs)) (analyze-log log))))
You could also have put these new restarts into parse-log-file
instead of
parse-log-entry
. However, you generally want to put restarts in the
lowest-level code possible.
It wouldn’t, though, be appropriate to move the skip-log-entry
restart into
~ parse-log-entry~ since that would cause parse-log-entry
to sometimes return
normally with ‘NIL’, the very thing you started out trying to avoid.
And it’d be an equally bad idea to remove the skip-log-entry
restart on the
theory that the condition handler could get the same effect by invoking the
use-value
restart with ‘NIL’ as the argument; that would require the
condition handler to have intimate knowledge of how the parse-log-file
works.
As it stands, the skip-log-entry
is a properly abstracted part of the
log-parsing
API.
Next: Other Uses for Conditions, Previous: Restarts, Up: Common Lisp Conditions [Contents][Index]