There are numerous options for what to do when an error occurs while processing a hunchentoot request. But unless I'm missing something, there's no option to (effectively) call invoke-debugger? While developing and debugging, I find this to seeing a log message etc.
It's rather easy to modify the standard process-request to call invoke-debugger, but wouldn't it make sense to have something like hunchentoot:*invoke-debugger-on-error-p* ?
On Fri, Nov 13, 2009 at 17:37, Frode V. Fjeld frode@netfonds.no wrote:
It's rather easy to modify the standard process-request to call invoke-debugger, but wouldn't it make sense to have something like hunchentoot:*invoke-debugger-on-error-p* ?
This is a common question which has been discussed a number of times. We've meant to put some debugging hints into the documentation, yet we've failed to do so, sorry about that.
The answer is: Use *break-on-signals* to have your Lisp enter the debugger when a certain condition type is signalled. See http://l1sp.org/cl/*break-on-signals* for details.
Hunchentoot used to have a special variable like you suggested, but we felt that it is better to use the language facilities rather than to invent special purpose mechanisms. Learning how to use *break-on-signals* is something that is useful anyway, so please try it out to see if it fits your needs.
On Fri, Nov 13, 2009 at 8:45 AM, Hans Hübner hans.huebner@gmail.com wrote:
On Fri, Nov 13, 2009 at 17:37, Frode V. Fjeld frode@netfonds.no wrote:
It's rather easy to modify the standard process-request to call invoke-debugger, but wouldn't it make sense to have something like hunchentoot:*invoke-debugger-on-error-p* ?
This is a common question which has been discussed a number of times. We've meant to put some debugging hints into the documentation, yet we've failed to do so, sorry about that.
The answer is: Use *break-on-signals* to have your Lisp enter the debugger when a certain condition type is signalled. See http://l1sp.org/cl/*break-on-signals* for details.
Hunchentoot used to have a special variable like you suggested, but we felt that it is better to use the language facilities rather than to invent special purpose mechanisms. Learning how to use *break-on-signals* is something that is useful anyway, so please try it out to see if it fits your needs.
In case *break-on-signals* doesn't meet your needs (for instance, if there are a lot of errors that get signaled and handled that can't be distinguished by type from the errors you want to go into the debugger on, you can also use something like this code which I got from someone on #lisp (antifuch's maybe?)
;;; An acceptor that invokes the debugger on errors: (defclass debuggable-acceptor (hunchentoot:acceptor) ())
(defvar *debug-connections* nil)
(defmethod process-connection ((*acceptor* debuggable-acceptor) (socket t)) (declare (ignore socket)) (if *debug-connections* (handler-bind ((error #'invoke-debugger)) (call-next-method)) (call-next-method)))
(defmethod acceptor-request-dispatcher ((*acceptor* debuggable-acceptor)) (let ((dispatcher (call-next-method))) (lambda (request) (handler-bind ((error #'invoke-debugger)) (funcall dispatcher request)))))
Then start your Hunchentoot instance with something like:
(start (make-instance 'debuggable-acceptor :port whatever))
-Peter
tbnl-devel site list tbnl-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/tbnl-devel
On Fri, Nov 13, 2009 at 17:37, Frode V. Fjeld frode@netfonds.no wrote:
It's rather easy to modify the standard process-request to call invoke-debugger, but wouldn't it make sense to have something like hunchentoot:*invoke-debugger-on-error-p* ?
Hans Hübner hans.huebner@gmail.com writes:
The answer is: Use *break-on-signals* [..]
Right, I did have the feeling that "I must be missing something here" :-) I actually knew of *break-on-signals* (having implemented it, even), I just didn't think of it.
Thanks,
Hans Hübner hans.huebner@gmail.com writes:
The answer is: Use *break-on-signals* [..]
Right, I did have the feeling that "I must be missing something here" :-) I actually knew of *break-on-signals* (having implemented it, even), I just didn't think of it.
I thought by now everyone would've realized that *break-on-signals* isn't the right tool here.
Not every signal is an error, and not every error bubbles up to the toplevel.
Leslie
"Leslie P. Polzer" sky@viridian-project.de writes:
Not every signal is an error, and not every error bubbles up to the toplevel.
Hm.. that is a valid point (or two). The switch should control whether hunchentoot's handler-bind should "decline" to handle the condition or not (i.e. whether to execute the THROW form). Not that I see many (signal 'error) in practice..
Also, looking at the relevant snippet of process-request, it strikes me as slightly odd that CATCH/THROW is used rather than BLOCK/RETURN-FROM. I think the latter is correct because it seems to me a lexical control transfer is intended. I'm unsure if the difference is anything but academic, though :-)
On Fri, Nov 13, 2009 at 7:08 PM, Leslie P. Polzer sky@viridian-project.de wrote:
Not every signal is an error
*break-on-signals* doesn't force you to break on every signal.
On Fri, Nov 13, 2009 at 11:49 AM, Edi Weitz edi@agharta.de wrote:
On Fri, Nov 13, 2009 at 7:08 PM, Leslie P. Polzer sky@viridian-project.de wrote:
Not every signal is an error
*break-on-signals* doesn't force you to break on every signal.
But it does force you, unless I'm deeply misunderstanding something, to break on every signal matching the type spec your specify, regardless of whether the error would have been handled by some higher level handler.
E.g.
CL-USER> (define-condition my-condition () ()) MY-CONDITION CL-USER> (defun foo () (signal 'my-condition)) FOO CL-USER> (foo) NIL CL-USER> (defun bar () (handler-case (foo) (my-condition () (format t "Handling my condition.")))) BAR CL-USER> (bar) Handling my condition. NIL CL-USER> (setq *break-on-signals* 'my-condition) MY-CONDITION CL-USER> (bar) ===> goes to debugger ; Evaluation aborted. CL-USER>
-Peter
Edi Weitz edi@agharta.de writes:
*break-on-signals* doesn't force you to break on every signal.
One simple use-case I believe where the *break-on-signals* approach is inappropriate is if some response is computed by means of e.g.
(if (ignore-errors (try-or-fail ...)) "It worked!" "Something went wrong.")
I would typically not want the debugger on every error signaled by try-or-fail, but I believe *break-on-signals* set to e.g. "error" would force that to happen.
Try-or-fail might be deep inside some library whose implementation I don't care about, or even inside of the lisp implementation itself.
On Sat, Nov 14, 2009 at 09:22, Frode V. Fjeld frode@netfonds.no wrote:
Edi Weitz edi@agharta.de writes:
*break-on-signals* doesn't force you to break on every signal.
One simple use-case I believe where the *break-on-signals* approach is inappropriate is if some response is computed by means of e.g.
(if (ignore-errors (try-or-fail ...)) "It worked!" "Something went wrong.")
We faced this problem a few times in the past and had the luxury to fix the underlying libraries. Normally, removing the use of ignore-errors is not hard to do, and quality code does not use it anyway. Face it, using (ignore-errors (parse-integer ...)) is nothing but stupid, but that was where I had to repair stuff in the past to make it debuggable.
I am not meaning to say that I would be strictly opposed to re-establishing a Hunchentoot-private way to control error handling. It is just that I have not felt restricted by using *break-on-signals* and that I consider code which uses errors to handle errors to be preferable in any case, Hunchentoot or not.
On Sat, Nov 14, 2009 at 9:37 AM, Hans Hübner hans.huebner@gmail.com wrote:
I am not meaning to say that I would be strictly opposed to re-establishing a Hunchentoot-private way to control error handling. It is just that I have not felt restricted by using *break-on-signals* and that I consider code which uses errors to handle errors to be preferable in any case, Hunchentoot or not.
Let me just say that I agree. The hows and whens of /maybe/ re-establishing Hunchentoot-specific error handling are still open due to lack of time (and that's one of the main reasons holding back a new release). But generally I think that CL has maybe the best condition system of all programming languages I know and we all don't use it enough. In an ideal world, *break-on-signals* would be the right solution to this problem. (And, yes, I've also used ignore-errors in places we I shouldn't have.)
Edi.
On Sat, Nov 14, 2009 at 2:46 AM, Edi Weitz edi@agharta.de wrote:
But generally I think that CL has maybe the best condition system of all programming languages I know and we all don't use it enough. In an ideal world, *break-on-signals* would be the right solution to this problem. (And, yes, I've also used ignore-errors in places we I shouldn't have.)
I agree with the first two bits (best in the world, not used enough) but I think I disagree with the latter (*break-on-signals* ought to be the right solution). The thing that makes the condition system great is that it separates the handling of conditions into not just two but three parts. (signaling, handling, and restarting). It seems to me a perfectly reasonable use of the condition system to signal a condition somewhere down low, handle it up high (but still in code that was called from Hunchentoot) and then restart in some application specific way. However if the condition signaled matches the type spec in *break-on-signals* that logic will be completely short circuited, landing you in the debugger for a condition that was actually going to be handled within the application code and would never have bothered Hunchentoot at all.
*break-on-signals* could possibly be made to work if you could come up with a type specifier that excluded all conditions of the sort I just described but included all unhandled conditions. But even if you could, that seems like a kludge to me--whether I want to end up in the debugger is not a function of the condition's type--it's a function of whether it's going to be handled before it percolates up to Hunchentoot code to deal with.
-Peter
On Sat, Nov 14, 2009 at 5:56 PM, Peter Seibel peter@gigamonkeys.com wrote:
I agree with the first two bits (best in the world, not used enough) but I think I disagree with the latter (*break-on-signals* ought to be the right solution). The thing that makes the condition system great is that it separates the handling of conditions into not just two but three parts. (signaling, handling, and restarting). It seems to me a perfectly reasonable use of the condition system to signal a condition somewhere down low, handle it up high (but still in code that was called from Hunchentoot) and then restart in some application specific way. However if the condition signaled matches the type spec in *break-on-signals* that logic will be completely short circuited, landing you in the debugger for a condition that was actually going to be handled within the application code and would never have bothered Hunchentoot at all.
*break-on-signals* could possibly be made to work if you could come up with a type specifier that excluded all conditions of the sort I just described but included all unhandled conditions. But even if you could, that seems like a kludge to me--whether I want to end up in the debugger is not a function of the condition's type--it's a function of whether it's going to be handled before it percolates up to Hunchentoot code to deal with.
Yes, I agree. I was probably a bit too over-enthusiastic with the third bit... :)
Still, I only have a finite amount of time. The Hunchentoot-specific error handling was thrown out with the 1.0.0 release and if we add something similar back in, I want it to be a reasonable, working, flexible, and well-documented solution. That takes time, and I'll do it when I have that time, this being not a priority for me right now.
Thanks, Edi.
On Sat, Nov 14, 2009 at 09:37:06AM +0100, Hans Hübner wrote:
We faced this problem a few times in the past and had the luxury to fix the underlying libraries. Normally, removing the use of ignore-errors is not hard to do, and quality code does not use it anyway. Face it, using (ignore-errors (parse-integer ...)) is nothing but stupid, but that was where I had to repair stuff in the past to make it debuggable.
A perfectly sane pattern however is catching a specific error, e.g.
(handler-case (parse-integer ...) (parse-error () nil))
This also triggers a break, of course.
Leslie