log HTTP errors in access log. close #317

This commit is contained in:
Benoit Chesneau 2012-04-26 18:17:55 +02:00
parent 1c27d369b4
commit 5f11713678
8 changed files with 35 additions and 15 deletions

View File

@ -21,6 +21,5 @@ def app(environ, start_response):
('Content-Length', str(len(data))),
('X-Gunicorn-Version', __version__)
]
start_response(status, response_headers)
return iter([data])

View File

@ -273,7 +273,7 @@ def validate_post_request(val):
elif largs == 2:
return wrap_post_request(val)
else:
raise TypeError("Value must have an arity of: 3")
raise TypeError("Value must have an arity of: 3")

View File

@ -157,7 +157,7 @@ class Logger(object):
status = resp.status.split(None, 1)[0]
atoms = {
'h': environ['REMOTE_ADDR'],
'h': environ.get('REMOTE_ADDR', '-'),
'l': '-',
'u': '-', # would be cool to get username from basic auth header
't': self.now(),

View File

@ -39,10 +39,9 @@ class FileWrapper:
return data
raise IndexError
def create(req, sock, client, server, cfg):
resp = Response(req, sock)
environ = {
def default_environ(req, sock, cfg):
return {
"wsgi.input": req.body,
"wsgi.errors": sys.stderr,
"wsgi.version": (1, 0),
@ -58,6 +57,12 @@ def create(req, sock, client, server, cfg):
"SERVER_PROTOCOL": "HTTP/%s" % ".".join(map(str, req.version))
}
def create(req, sock, client, server, cfg):
resp = Response(req, sock)
environ = default_environ(req, sock, cfg)
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
# may not qualify the remote addr:
# http://www.ietf.org/rfc/rfc3875

View File

@ -125,8 +125,9 @@ def load_class(uri, default="sync", section="gunicorn.workers"):
return pkg_resources.load_entry_point("gunicorn",
section, uri)
except ImportError:
raise RuntimeError("class uri invalid or not found")
except ImportError, e:
raise RuntimeError("class uri invalid or not found: [%s]",
str(e))
klass = components.pop(-1)
mod = __import__('.'.join(components))
for comp in components[1:]:

View File

@ -26,6 +26,7 @@ class AsyncWorker(base.Worker):
raise NotImplementedError()
def handle(self, client, addr):
req = None
try:
parser = http.RequestParser(self.cfg, client)
try:
@ -38,6 +39,8 @@ class AsyncWorker(base.Worker):
self.handle_request(req, client, addr)
except StopIteration, e:
self.log.debug("Closing connection. %s", e)
except Exception, e:
self.handle_error(req, client, addr, e)
except socket.error, e:
if e[0] not in (errno.EPIPE, errno.ECONNRESET):
self.log.exception("Socket error processing request.")
@ -47,14 +50,14 @@ class AsyncWorker(base.Worker):
else:
self.log.debug("Ignoring EPIPE")
except Exception, e:
self.handle_error(client, e)
self.handle_error(req, client, addr, e)
finally:
util.close(client)
def handle_request(self, req, sock, addr):
request_start = datetime.now()
try:
self.cfg.pre_request(self, req)
request_start = datetime.now()
resp, environ = wsgi.create(req, sock, addr, self.address, self.cfg)
self.nr += 1
if self.alive and self.nr >= self.max_requests:

View File

@ -3,6 +3,7 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
from datetime import datetime
import os
import signal
import sys
@ -11,11 +12,10 @@ import traceback
from gunicorn import util
from gunicorn.workers.workertmp import WorkerTmp
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, \
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, \
LimitRequestLine, LimitRequestHeaders
from gunicorn.http.wsgi import default_environ, Response
class Worker(object):
@ -125,7 +125,8 @@ class Worker(object):
self.alive = False
sys.exit(0)
def handle_error(self, client, exc):
def handle_error(self, req, client, addr, exc):
request_start = datetime.now()
if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,
InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,)):
@ -157,6 +158,16 @@ class Worker(object):
reason = "Internal Server Error"
mesg = ""
if req is not None:
request_time = datetime.now() - request_start
environ = default_environ(req, client, self.cfg)
environ['REMOTE_ADDR'] = addr[0]
environ['REMOTE_PORT'] = str(addr[1])
resp = Response(req, client)
resp.status = "%s %s" % (status_int, reason)
resp.response_length = len(mesg)
self.log.access(resp, req, environ, request_time)
if self.debug:
tb = traceback.format_exc()
mesg += "<h2>Traceback:</h2>\n<pre>%s</pre>" % tb

View File

@ -65,6 +65,7 @@ class SyncWorker(base.Worker):
raise
def handle(self, client, addr):
req = None
try:
parser = http.RequestParser(self.cfg, client)
req = parser.next()
@ -77,7 +78,7 @@ class SyncWorker(base.Worker):
else:
self.log.debug("Ignoring EPIPE")
except Exception, e:
self.handle_error(client, e)
self.handle_error(req, client, addr, e)
finally:
util.close(client)
@ -113,7 +114,7 @@ class SyncWorker(base.Worker):
raise
except Exception, e:
# Only send back traceback in HTTP in debug mode.
self.handle_error(client, e)
self.handle_error(req, client, addr, e)
return
finally:
try: