| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
- # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
- """
- Middleware for logging requests, using Apache combined log format
- """
- import logging
- import six
- import time
- from six.moves.urllib.parse import quote
- class TransLogger(object):
- """
- This logging middleware will log all requests as they go through.
- They are, by default, sent to a logger named ``'wsgi'`` at the
- INFO level.
- If ``setup_console_handler`` is true, then messages for the named
- logger will be sent to the console.
- """
- format = ('%(REMOTE_ADDR)s - %(REMOTE_USER)s [%(time)s] '
- '"%(REQUEST_METHOD)s %(REQUEST_URI)s %(HTTP_VERSION)s" '
- '%(status)s %(bytes)s "%(HTTP_REFERER)s" "%(HTTP_USER_AGENT)s"')
- def __init__(self, application,
- logger=None,
- format=None,
- logging_level=logging.INFO,
- logger_name='wsgi',
- setup_console_handler=True,
- set_logger_level=logging.DEBUG):
- if format is not None:
- self.format = format
- self.application = application
- self.logging_level = logging_level
- self.logger_name = logger_name
- if logger is None:
- self.logger = logging.getLogger(self.logger_name)
- if setup_console_handler:
- console = logging.StreamHandler()
- console.setLevel(logging.DEBUG)
- # We need to control the exact format:
- console.setFormatter(logging.Formatter('%(message)s'))
- self.logger.addHandler(console)
- self.logger.propagate = False
- if set_logger_level is not None:
- self.logger.setLevel(set_logger_level)
- else:
- self.logger = logger
- def __call__(self, environ, start_response):
- start = time.localtime()
- req_uri = quote(environ.get('SCRIPT_NAME', '')
- + environ.get('PATH_INFO', ''))
- if environ.get('QUERY_STRING'):
- req_uri += '?'+environ['QUERY_STRING']
- method = environ['REQUEST_METHOD']
- def replacement_start_response(status, headers, exc_info=None):
- # @@: Ideally we would count the bytes going by if no
- # content-length header was provided; but that does add
- # some overhead, so at least for now we'll be lazy.
- bytes = None
- for name, value in headers:
- if name.lower() == 'content-length':
- bytes = value
- self.write_log(environ, method, req_uri, start, status, bytes)
- return start_response(status, headers)
- return self.application(environ, replacement_start_response)
- def write_log(self, environ, method, req_uri, start, status, bytes):
- if bytes is None:
- bytes = '-'
- if time.daylight:
- offset = time.altzone / 60 / 60 * -100
- else:
- offset = time.timezone / 60 / 60 * -100
- if offset >= 0:
- offset = "+%0.4d" % (offset)
- elif offset < 0:
- offset = "%0.4d" % (offset)
- remote_addr = '-'
- if environ.get('HTTP_X_FORWARDED_FOR'):
- remote_addr = environ['HTTP_X_FORWARDED_FOR']
- elif environ.get('REMOTE_ADDR'):
- remote_addr = environ['REMOTE_ADDR']
- d = {
- 'REMOTE_ADDR': remote_addr,
- 'REMOTE_USER': environ.get('REMOTE_USER') or '-',
- 'REQUEST_METHOD': method,
- 'REQUEST_URI': req_uri,
- 'HTTP_VERSION': environ.get('SERVER_PROTOCOL'),
- 'time': time.strftime('%d/%b/%Y:%H:%M:%S ', start) + offset,
- 'status': status.split(None, 1)[0],
- 'bytes': bytes,
- 'HTTP_REFERER': environ.get('HTTP_REFERER', '-'),
- 'HTTP_USER_AGENT': environ.get('HTTP_USER_AGENT', '-'),
- }
- message = self.format % d
- self.logger.log(self.logging_level, message)
- def make_filter(
- app, global_conf,
- logger_name='wsgi',
- format=None,
- logging_level=logging.INFO,
- setup_console_handler=True,
- set_logger_level=logging.DEBUG):
- from paste.util.converters import asbool
- if isinstance(logging_level, (six.binary_type, six.text_type)):
- logging_level = logging._levelNames[logging_level]
- if isinstance(set_logger_level, (six.binary_type, six.text_type)):
- set_logger_level = logging._levelNames[set_logger_level]
- return TransLogger(
- app,
- format=format or None,
- logging_level=logging_level,
- logger_name=logger_name,
- setup_console_handler=asbool(setup_console_handler),
- set_logger_level=set_logger_level)
- make_filter.__doc__ = TransLogger.__doc__
|