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]