|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +import logging |
| 3 | +import sys |
| 4 | + |
| 5 | +import cherrypy |
| 6 | +from cherrypy import _cplogging, _cperror |
| 7 | +from django.http import HttpResponseServerError |
| 8 | + |
| 9 | +class HTTPLogger(_cplogging.LogManager): |
| 10 | + def __init__(self, app): |
| 11 | + _cplogging.LogManager.__init__(self, id(self), cherrypy.log.logger_root) |
| 12 | + self.app = app |
| 13 | + |
| 14 | + def __call__(self, environ, start_response): |
| 15 | + """ |
| 16 | + Called as part of the WSGI stack to log the incoming request |
| 17 | + and its response using the common log format. If an error bubbles up |
| 18 | + to this middleware, we log it as such. |
| 19 | + """ |
| 20 | + try: |
| 21 | + response = self.app(environ, start_response) |
| 22 | + self.access(environ, response) |
| 23 | + return response |
| 24 | + except: |
| 25 | + self.error(traceback=True) |
| 26 | + return HttpResponseServerError(_cperror.format_exc()) |
| 27 | + |
| 28 | + def access(self, environ, response): |
| 29 | + """ |
| 30 | + Special method that logs a request following the common |
| 31 | + log format. This is mostly taken from CherryPy and adapted |
| 32 | + to the WSGI's style of passing information. |
| 33 | + """ |
| 34 | + |
| 35 | + if 'status_code' not in dir(response): |
| 36 | + return |
| 37 | + |
| 38 | + atoms = {'h': environ.get('REMOTE_ADDR', ''), |
| 39 | + 'l': '-', |
| 40 | + 'u': "-", |
| 41 | + 't': self.time(), |
| 42 | + 'r': "%s %s %s" % (environ['REQUEST_METHOD'], environ['REQUEST_URI'], environ['SERVER_PROTOCOL']), |
| 43 | + 's': response.status_code, |
| 44 | + 'b': str(len(response.content)), |
| 45 | + 'f': environ.get('HTTP_REFERER', ''), |
| 46 | + 'a': environ.get('HTTP_USER_AGENT', '') |
| 47 | + } |
| 48 | + for k, v in atoms.items(): |
| 49 | + if not isinstance(v, str): |
| 50 | + v = str(v) |
| 51 | + # Fortunately, repr(str) escapes unprintable chars, \n, \t, etc |
| 52 | + # and backslash for us. All we have to do is strip the quotes. |
| 53 | + v = repr(v)[1:-1] |
| 54 | + # Escape double-quote. |
| 55 | + atoms[k] = v.replace('"', '\\"') |
| 56 | + |
| 57 | + try: |
| 58 | + self.access_log.log(logging.INFO, self.access_log_format.format(**atoms)) |
| 59 | + except: |
| 60 | + self.error(traceback=True) |
0 commit comments