mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
log HTTP errors in access log. close #317
This commit is contained in:
parent
1c27d369b4
commit
5f11713678
@ -21,6 +21,5 @@ def app(environ, start_response):
|
|||||||
('Content-Length', str(len(data))),
|
('Content-Length', str(len(data))),
|
||||||
('X-Gunicorn-Version', __version__)
|
('X-Gunicorn-Version', __version__)
|
||||||
]
|
]
|
||||||
|
|
||||||
start_response(status, response_headers)
|
start_response(status, response_headers)
|
||||||
return iter([data])
|
return iter([data])
|
||||||
|
|||||||
@ -273,7 +273,7 @@ def validate_post_request(val):
|
|||||||
elif largs == 2:
|
elif largs == 2:
|
||||||
return wrap_post_request(val)
|
return wrap_post_request(val)
|
||||||
else:
|
else:
|
||||||
raise TypeError("Value must have an arity of: 3")
|
raise TypeError("Value must have an arity of: 3")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -157,7 +157,7 @@ class Logger(object):
|
|||||||
|
|
||||||
status = resp.status.split(None, 1)[0]
|
status = resp.status.split(None, 1)[0]
|
||||||
atoms = {
|
atoms = {
|
||||||
'h': environ['REMOTE_ADDR'],
|
'h': environ.get('REMOTE_ADDR', '-'),
|
||||||
'l': '-',
|
'l': '-',
|
||||||
'u': '-', # would be cool to get username from basic auth header
|
'u': '-', # would be cool to get username from basic auth header
|
||||||
't': self.now(),
|
't': self.now(),
|
||||||
|
|||||||
@ -39,10 +39,9 @@ class FileWrapper:
|
|||||||
return data
|
return data
|
||||||
raise IndexError
|
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.input": req.body,
|
||||||
"wsgi.errors": sys.stderr,
|
"wsgi.errors": sys.stderr,
|
||||||
"wsgi.version": (1, 0),
|
"wsgi.version": (1, 0),
|
||||||
@ -58,6 +57,12 @@ def create(req, sock, client, server, cfg):
|
|||||||
"SERVER_PROTOCOL": "HTTP/%s" % ".".join(map(str, req.version))
|
"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
|
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
|
||||||
# may not qualify the remote addr:
|
# may not qualify the remote addr:
|
||||||
# http://www.ietf.org/rfc/rfc3875
|
# http://www.ietf.org/rfc/rfc3875
|
||||||
|
|||||||
@ -125,8 +125,9 @@ def load_class(uri, default="sync", section="gunicorn.workers"):
|
|||||||
|
|
||||||
return pkg_resources.load_entry_point("gunicorn",
|
return pkg_resources.load_entry_point("gunicorn",
|
||||||
section, uri)
|
section, uri)
|
||||||
except ImportError:
|
except ImportError, e:
|
||||||
raise RuntimeError("class uri invalid or not found")
|
raise RuntimeError("class uri invalid or not found: [%s]",
|
||||||
|
str(e))
|
||||||
klass = components.pop(-1)
|
klass = components.pop(-1)
|
||||||
mod = __import__('.'.join(components))
|
mod = __import__('.'.join(components))
|
||||||
for comp in components[1:]:
|
for comp in components[1:]:
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class AsyncWorker(base.Worker):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def handle(self, client, addr):
|
def handle(self, client, addr):
|
||||||
|
req = None
|
||||||
try:
|
try:
|
||||||
parser = http.RequestParser(self.cfg, client)
|
parser = http.RequestParser(self.cfg, client)
|
||||||
try:
|
try:
|
||||||
@ -38,6 +39,8 @@ class AsyncWorker(base.Worker):
|
|||||||
self.handle_request(req, client, addr)
|
self.handle_request(req, client, addr)
|
||||||
except StopIteration, e:
|
except StopIteration, e:
|
||||||
self.log.debug("Closing connection. %s", e)
|
self.log.debug("Closing connection. %s", e)
|
||||||
|
except Exception, e:
|
||||||
|
self.handle_error(req, client, addr, e)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
if e[0] not in (errno.EPIPE, errno.ECONNRESET):
|
if e[0] not in (errno.EPIPE, errno.ECONNRESET):
|
||||||
self.log.exception("Socket error processing request.")
|
self.log.exception("Socket error processing request.")
|
||||||
@ -47,14 +50,14 @@ class AsyncWorker(base.Worker):
|
|||||||
else:
|
else:
|
||||||
self.log.debug("Ignoring EPIPE")
|
self.log.debug("Ignoring EPIPE")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.handle_error(client, e)
|
self.handle_error(req, client, addr, e)
|
||||||
finally:
|
finally:
|
||||||
util.close(client)
|
util.close(client)
|
||||||
|
|
||||||
def handle_request(self, req, sock, addr):
|
def handle_request(self, req, sock, addr):
|
||||||
|
request_start = datetime.now()
|
||||||
try:
|
try:
|
||||||
self.cfg.pre_request(self, req)
|
self.cfg.pre_request(self, req)
|
||||||
request_start = datetime.now()
|
|
||||||
resp, environ = wsgi.create(req, sock, addr, self.address, self.cfg)
|
resp, environ = wsgi.create(req, sock, addr, self.address, self.cfg)
|
||||||
self.nr += 1
|
self.nr += 1
|
||||||
if self.alive and self.nr >= self.max_requests:
|
if self.alive and self.nr >= self.max_requests:
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
@ -11,11 +12,10 @@ import traceback
|
|||||||
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
from gunicorn.workers.workertmp import WorkerTmp
|
from gunicorn.workers.workertmp import WorkerTmp
|
||||||
|
|
||||||
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, \
|
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, \
|
||||||
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, \
|
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, \
|
||||||
LimitRequestLine, LimitRequestHeaders
|
LimitRequestLine, LimitRequestHeaders
|
||||||
|
from gunicorn.http.wsgi import default_environ, Response
|
||||||
|
|
||||||
class Worker(object):
|
class Worker(object):
|
||||||
|
|
||||||
@ -125,7 +125,8 @@ class Worker(object):
|
|||||||
self.alive = False
|
self.alive = False
|
||||||
sys.exit(0)
|
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,
|
if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,
|
||||||
InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,)):
|
InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,)):
|
||||||
|
|
||||||
@ -157,6 +158,16 @@ class Worker(object):
|
|||||||
reason = "Internal Server Error"
|
reason = "Internal Server Error"
|
||||||
mesg = ""
|
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:
|
if self.debug:
|
||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
mesg += "<h2>Traceback:</h2>\n<pre>%s</pre>" % tb
|
mesg += "<h2>Traceback:</h2>\n<pre>%s</pre>" % tb
|
||||||
|
|||||||
@ -65,6 +65,7 @@ class SyncWorker(base.Worker):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def handle(self, client, addr):
|
def handle(self, client, addr):
|
||||||
|
req = None
|
||||||
try:
|
try:
|
||||||
parser = http.RequestParser(self.cfg, client)
|
parser = http.RequestParser(self.cfg, client)
|
||||||
req = parser.next()
|
req = parser.next()
|
||||||
@ -77,7 +78,7 @@ class SyncWorker(base.Worker):
|
|||||||
else:
|
else:
|
||||||
self.log.debug("Ignoring EPIPE")
|
self.log.debug("Ignoring EPIPE")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.handle_error(client, e)
|
self.handle_error(req, client, addr, e)
|
||||||
finally:
|
finally:
|
||||||
util.close(client)
|
util.close(client)
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ class SyncWorker(base.Worker):
|
|||||||
raise
|
raise
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
# Only send back traceback in HTTP in debug mode.
|
# Only send back traceback in HTTP in debug mode.
|
||||||
self.handle_error(client, e)
|
self.handle_error(req, client, addr, e)
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user