For error handling just supply your own function for *http-error-handler*. From there you can send an email as well or/and show a message to the user.<br>Something like this:<br><br>(setq *http-error-handler* 'my-error-handler)
<br><br>(defun my-error-handler (return-code)<br> (if (= +http-moved-temporarily+ return-code)<br> (return-from my-error-handler))<br> (let ((backtrace (get-backtrace 0))<br> (session (start-session))) ;; retrieve stuff out of your session
<br> (send-email "Critical error" (format nil "RetCode: ~a, Backtrace: ~a" return-code backtrace)) ;; My email function<br> (with-html<br> (:html <br> (:head (:title "Error Page")
<br> (:link :rel "stylesheet" :type "text/css" :href *design-css*)<br> (:script :language "JavaScript" :src *js-main-script* :type "text/javascript" ""))
<br> (:body<br> (:h2 "Sorry, a server-side error has occured.")))<br><br>Note that you need to make the size of the html code (css, javascript + html) of the error page more than 512Bytes so that MS IE
7.0 would show your information instead of its own message.<br><br>Andrew<br><br><br><div><span class="gmail_quote">On 4/15/07, <b class="gmail_sendername">Victor Kryukov</b> <<a href="mailto:victor.kryukov@gmail.com">
victor.kryukov@gmail.com</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Hello list,<br><br>I want to accomplish the following: every time a lisp error happens,
<br>the whole backtrace and some additional information is sent to my mail<br>account. The question is, what is the best way to do it with<br>Hunchentoot? (I do know how to send email messages from lisp with the<br>help of mel-base).
<br><br>The second question is: how do you use CLSQL thread-safely with<br>Hunchentoot / SBCL? SBCL don't provide thread properties, so my first<br>solution[1] was to create a hash-table and to assign each thread a<br>
connection, to check from every thread whether it already has a<br>connection, and then to clean that hash-table periodically, closing<br>connections for dead threads. That worked pretty well, but I was<br>afraid of exhausting limit of database threads somehow, so I switched
<br>to the second solution.<br><br>The second solution[2] is to open new connection every time I need to<br>save something to database or read something from it, and to close it<br>right after that. That of course solves connection limit problem
<br>(unless I have very many users simultaneously, which is not expected<br>in the near term), however it's much slower.<br><br>Anybody can share his/her strategy?<br><br>Best regards,<br>Victor.<br><br>[1] <a href="http://paste.lisp.org/display/39787">
http://paste.lisp.org/display/39787</a><br>(defparameter *database-mutex* (sb-thread:make-mutex :name "database lock"))<br>(defparameter *threads-connection* (make-hash-table))<br><br>(defun setup-connection ()<br>
(connect '("localhost" "lj" "victor" "victor")<br> :database-type :postgresql :if-exists :new))<br><br> (defun db ()<br> (handler-case<br> (sb-thread:with-mutex (*database-mutex*)
<br> (or (gethash sb-thread:*current-thread* *threads-connection*)<br> (setf (gethash sb-thread:*current-thread* *threads-connection*)<br> (setup-connection))))<br> (error () (progn<br> (close-old-connections)
<br> (db)))))<br><br>(defun close-old-connections ()<br> (maphash #'(lambda (thread connection)<br> (unless (sb-thread:thread-alive-p thread)<br> (clsql:disconnect :database connection)
<br> (remhash thread *threads-connection*)))<br> *threads-connection*))<br><br> (let ((old-select (symbol-function 'clsql:select)))<br> (defun select (&rest args)<br> (let ((*default-database* (db)))
<br> (apply old-select args))))<br><br> (let ((old-insert-records (symbol-function 'insert-records)))<br> (defun insert-records (&rest args)<br> (apply old-insert-records :database (db) args)))<br><br>
<br>[2] <a href="http://paste.lisp.org/display/39787#1">http://paste.lisp.org/display/39787#1</a><br>(defun db ()<br> (connect *connection-spec*<br> :database-type :postgresql :if-exists :new))<br><br>(let ((old-select (symbol-function 'clsql:select)))
<br> (defun select (&rest args)<br> (let ((clsql:*default-database* (db)))<br> (prog1<br> (apply old-select args)<br> (disconnect :database clsql:*default-database*)))))<br><br>(let ((old-insert-records (symbol-function 'insert-records)))
<br> (defun insert-records (&rest args)<br> (let ((db (db)))<br> (prog1<br> (apply old-insert-records :database db args)<br> (disconnect :database db)))))<br><br><br><br>--<br>Yours Sincerely,
<br>Victor Kryukov<br>_______________________________________________<br>tbnl-devel site list<br><a href="mailto:tbnl-devel@common-lisp.net">tbnl-devel@common-lisp.net</a><br><a href="http://common-lisp.net/mailman/listinfo/tbnl-devel">
http://common-lisp.net/mailman/listinfo/tbnl-devel</a><br></blockquote></div><br>