Error Handling in Production Mode
It's unlikely that a Python web application will never cause a traceback. Even if the application is completely flawless the database server could die or some other things break you have no control over. And because of that it's important to handle such cases. Thankfully python provides the logging module which can easily handle such cases for you.
Generally speaking the following things are pretty common in any kind of application
- warnings. Sometimes fishing things happen that could cause problems but don't immediately affect the functionality of the application. For example an application could warn if someone sent a fake request to a resource which is only available to XMLHttpRequests normally and the application did not know what to do. This could mean that someone wants to exploit your code so it's a good idea to issue some warnings when the application returns a 400 bad request.
- tracebacks. Tracebacks caused by uncatched exceptions are like errors but with machine generated detail information. Usually caused because something broke you haven't thought of.
- errors. Errors are hand written error messages to the logging system. They maybe abort the request with some 500 status code but additionally issue a hand written error message to the logger, rather than raising an exception. That could be useful if the database is left in an inconsistent state and you want to log an error message.
The good thing is that all these things can be handled easily with some help of the logging module. And it does that in a very good way. It can send logging output via EMail, to the syslog, the NT error protocol, or via sockets to a remote server. Or you just subclass the handler and add your own logic like logging into a database.
The basic logger configuration is explained in the documentation but below a small example of how you can use the logger module with a WSGI application in a simple way:
from werkzeug import BaseRequest, BaseResponse from werkzeug.exceptions import InternalServerError import logging # this could come from some sort of configuration of course. MANAGERS = ['foo@example.org', 'bar@example.org'] # set up the logger. Here you can be creative and filter a bit, # but for simplicity we just set the logging to ERROR and higher # and tell it to send us mails. logger = logging.getLogger('myapplication') handler = SMTPHandler('localhost', MANAGERS, 'Application Error') handler.setLevel(logging.ERROR) logger.addHandler(handler) # something more fancy here, that's displayed on tracebacks server_error_response = InternalServerError().get_response() def application(environ, start_response): """The WSGI application.""" request = BaseRequest(environ) try: # do all the application specific dispatching here that # generates the response object. response = execute_view(request) except: # whoops. an error occurred. log it and return a simple # internal server error response. logger.exception('Application error occurred at %s', request.path.encode('utf-8')) response = server_error_response return response(environ, start_response)
Of course for a real application you should really bind that to the application config so that you can toggle debug mode and production mode. In debug mode the error handler would not send mails for errors but log all logging stuff to stderr. And catching the exceptions during debugging is a bad idea too because you can't use the interactive debugger then.
If you want to create tickets in a trac for application errors you can have a look at the PythoNTracLogHandler snippet on trac-hacks.