diff --git a/src/eddn/Gateway.py b/src/eddn/Gateway.py index b469036..95387c5 100644 --- a/src/eddn/Gateway.py +++ b/src/eddn/Gateway.py @@ -14,6 +14,7 @@ from typing import Dict from urllib.parse import parse_qs import gevent +import gevent.pywsgi import simplejson import zmq.green as zmq from gevent import monkey @@ -424,6 +425,55 @@ def apply_cors() -> None: ) +class EDDNWSGIHandler(gevent.pywsgi.WSGIHandler): + """iHandles overriding request logging.""" + + def format_request(self): + """ + Format information about the request for logging. + + The default causes, e.g.: + + - - [2022-03-12 16:44:39] "POST /upload/ HTTP/1.1" 400 399 0.000566 + + and makes no attempt to handle reverse proxying where we know that + X-Forwarded-For has been set by our reverse proxy. So this will use + that header if present to output the correct IP. + + Also, as we're pointing output at our logger, there is no need to + include a timestamp in the output. + + This is why we're overriding *this* and not `handle_one_response()`, + where we'd change self.client_address there instead. This does, + unfortunately, mean re-creating most of the super-class'es version + of the function. + + Resulting output: + + 2022-03-12 16:44:39.132 - INFO - pywsgi:1226: - - "POST /upload/ HTTP/1.1" 400 399 0.000566 + """ + # Start with the same as the super-class would use... + client_address = self.client_address[0] if isinstance(self.client_address, tuple) else self.client_address + + # ... but now over-ride it if the header is set. + if self.environ.get("HTTP_X_FORWARDED_FOR"): + client_address = self.environ["HTTP_X_FORWARDED_FOR"] + + length = self.response_length or '-' + + if self.time_finish: + d = self.time_finish - self.time_start + delta = f"{d:6f}" + + else: + delta = '-' + + # This differs from the super-class version in not having a datestamp + return f"{client_address or '-'} - - \"{self.requestline or '-'}\"" \ + f" {(self._orig_status or self.status or '000').split()[0]}" \ + f" {length} {delta}" + + def main() -> None: """Handle setting up and running the bottle app.""" cl_args = parse_cl_args() @@ -434,10 +484,13 @@ def main() -> None: configure() app.add_hook("after_request", apply_cors) + # app.install(custom_logging) app.run( host=Settings.GATEWAY_HTTP_BIND_ADDRESS, port=Settings.GATEWAY_HTTP_PORT, server="gevent", + log=gevent.pywsgi.LoggingLogAdapter(logger), + handler_class=EDDNWSGIHandler, )