From 15bdf51adb3def3ec90a69bb655ae42de61e364e 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 | 15 +++++-------- uvicorn/protocols/http/h11_impl.py | 20 +++++++++++++---- uvicorn/protocols/http/httptools_impl.py | 28 +++++++++++++++++------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/uvicorn/logging.py b/uvicorn/logging.py index ab6261d14..3a116d981 100644 --- a/uvicorn/logging.py +++ b/uvicorn/logging.py @@ -95,21 +95,16 @@ def default(code: int) -> str: return status_and_phrase 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] + status_code = self.get_status_code(int(record.__dict__["status"])) + method = record.__dict__["method"] + full_path = record.__dict__["full_path"] + http_version = record.__dict__["http_version"] request_line = f"{method} {full_path} HTTP/{http_version}" if self.use_colors: request_line = click.style(request_line, bold=True) + recordcopy = copy(record) 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")