From 827dce31a54468f363a09bfd2da23696054f09f0 Mon Sep 17 00:00:00 2001 From: Martynov Maxim Date: Thu, 16 Nov 2023 12:26:05 +0300 Subject: [PATCH] Pass request info as log record extra fields --- uvicorn/logging.py | 16 +++++--------- uvicorn/protocols/http/h11_impl.py | 20 +++++++++++++---- uvicorn/protocols/http/httptools_impl.py | 28 +++++++++++++++++------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/uvicorn/logging.py b/uvicorn/logging.py index ab6261d14..c5d6f3af0 100644 --- a/uvicorn/logging.py +++ b/uvicorn/logging.py @@ -96,20 +96,16 @@ def default(code: int) -> str: def formatMessage(self, record: logging.LogRecord) -> str: recordcopy = copy(record) - ( - client_addr, - method, - full_path, - http_version, - status_code, - ) = recordcopy.args # type: ignore[misc] - status_code = self.get_status_code(int(status_code)) # type: ignore[arg-type] - request_line = f"{method} {full_path} HTTP/{http_version}" + status_code = self.get_status_code(int(recordcopy.status)) # type: ignore[attr-defined] + request_line = "{} {} HTTP/{}".format( + recordcopy.method, # type: ignore[attr-defined] + recordcopy.full_path, # type: ignore[attr-defined] + recordcopy.http_version, # type: ignore[attr-defined] + ) if self.use_colors: request_line = click.style(request_line, bold=True) recordcopy.__dict__.update( { - "client_addr": client_addr, "request_line": request_line, "status_code": status_code, } diff --git a/uvicorn/protocols/http/h11_impl.py b/uvicorn/protocols/http/h11_impl.py index d0f2b2a5e..59ab42555 100644 --- a/uvicorn/protocols/http/h11_impl.py +++ b/uvicorn/protocols/http/h11_impl.py @@ -474,13 +474,25 @@ async def send(self, message: ASGISendEvent) -> None: headers = headers + [CLOSE_HEADER] if self.access_log: + client_addr = get_client_addr(self.scope) + method = self.scope["method"] + http_version = self.scope["http_version"] + full_path = get_path_with_query_string(self.scope) + self.access_logger.info( '%s - "%s %s HTTP/%s" %d', - get_client_addr(self.scope), - self.scope["method"], - get_path_with_query_string(self.scope), - self.scope["http_version"], + client_addr, + method, + full_path, + http_version, status, + extra={ + "client_addr": client_addr, + "method": method, + "full_path": full_path, + "http_version": http_version, + "status": status, + }, ) # Write response status line and headers diff --git a/uvicorn/protocols/http/httptools_impl.py b/uvicorn/protocols/http/httptools_impl.py index 60debaf8f..28f720847 100644 --- a/uvicorn/protocols/http/httptools_impl.py +++ b/uvicorn/protocols/http/httptools_impl.py @@ -467,24 +467,36 @@ async def send(self, message: ASGISendEvent) -> None: self.response_started = True self.waiting_for_100_continue = False - status_code = message["status"] + status = message["status"] headers = self.default_headers + list(message.get("headers", [])) if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers: headers = headers + [CLOSE_HEADER] if self.access_log: + client_addr = get_client_addr(self.scope) + method = self.scope["method"] + http_version = self.scope["http_version"] + full_path = get_path_with_query_string(self.scope) + self.access_logger.info( '%s - "%s %s HTTP/%s" %d', - get_client_addr(self.scope), - self.scope["method"], - get_path_with_query_string(self.scope), - self.scope["http_version"], - status_code, + client_addr, + method, + full_path, + http_version, + status, + extra={ + "client_addr": client_addr, + "method": method, + "full_path": full_path, + "http_version": http_version, + "status": status, + }, ) # Write response status line and headers - content = [STATUS_LINE[status_code]] + content = [STATUS_LINE[status]] for name, value in headers: if HEADER_RE.search(name): @@ -503,7 +515,7 @@ async def send(self, message: ASGISendEvent) -> None: self.keep_alive = False content.extend([name, b": ", value, b"\r\n"]) - if self.chunked_encoding is None and self.scope["method"] != "HEAD" and status_code not in (204, 304): + if self.chunked_encoding is None and self.scope["method"] != "HEAD" and status not in (204, 304): # Neither content-length nor transfer-encoding specified self.chunked_encoding = True content.append(b"transfer-encoding: chunked\r\n")