From 22a40f53d3188cf0410201dfdebef5a274f2c45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 24 Nov 2024 13:16:07 +0530 Subject: [PATCH 1/4] Update server log messages to include specific addresses Update server log messages to display specific addresses. * Add `get_interface_ip` function to retrieve the IP address of an external interface. * Update `_log_started_message` method to include log messages for 'Running on all addresses (0.0.0.0)', 'Running on http://127.0.0.1:8080', and 'Running on http://192.168.1.10:8080'. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/encode/uvicorn?shareId=XXXX-XXXX-XXXX-XXXX). --- uvicorn/server.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/uvicorn/server.py b/uvicorn/server.py index f14026f16..a80e5b1c5 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -35,6 +35,23 @@ logger = logging.getLogger("uvicorn.error") +def get_interface_ip(family: socket.AddressFamily) -> str: + """Get the IP address of an external interface. Used when binding to + 0.0.0.0 or ::1 to show a more useful URL. + + :meta private: + """ + # arbitrary private address + host = "fd31:f903:5ab5:1::1" if family == socket.AF_INET6 else "10.253.155.219" + + with socket.socket(family, socket.SOCK_DGRAM) as s: + try: + s.connect((host, 58162)) + except OSError: + return "::1" if family == socket.AF_INET6 else "127.0.0.1" + + return s.getsockname()[0] # type: ignore + class ServerState: """ @@ -219,6 +236,12 @@ def _log_started_message(self, listeners: Sequence[socket.SocketType]) -> None: extra={"color_message": color_message}, ) + if host == "0.0.0.0": + localhost = "127.0.0.1" + display_hostname = get_interface_ip(socket.AF_INET) + logger.info(f"Running on {protocol_name}://{localhost}:{port}") + logger.info(f"Running on {protocol_name}://{display_hostname}:{port}") + async def main_loop(self) -> None: counter = 0 should_exit = await self.on_tick(counter) From 6b4ac28573371cb142167a5e7c68e269dc4e6723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 24 Nov 2024 13:23:07 +0530 Subject: [PATCH 2/4] Add a blank line in `uvicorn/server.py` after the logger initialization --- uvicorn/server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uvicorn/server.py b/uvicorn/server.py index a80e5b1c5..50cf22956 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -35,6 +35,7 @@ logger = logging.getLogger("uvicorn.error") + def get_interface_ip(family: socket.AddressFamily) -> str: """Get the IP address of an external interface. Used when binding to 0.0.0.0 or ::1 to show a more useful URL. From ac31bc7681c942f621c00ce4f387acca06753fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 24 Nov 2024 13:24:51 +0530 Subject: [PATCH 3/4] Lint: Remove type ignore comment from `s.getsockname()[0]` return statement --- uvicorn/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uvicorn/server.py b/uvicorn/server.py index 50cf22956..d17eccc50 100644 --- a/uvicorn/server.py +++ b/uvicorn/server.py @@ -51,7 +51,7 @@ def get_interface_ip(family: socket.AddressFamily) -> str: except OSError: return "::1" if family == socket.AF_INET6 else "127.0.0.1" - return s.getsockname()[0] # type: ignore + return s.getsockname()[0] class ServerState: From ea1e3334a9cf422091ebad885f3014c1c675387d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 24 Nov 2024 13:32:08 +0530 Subject: [PATCH 4/4] Add test case for log messages for all addresses --- tests/test_server.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_server.py b/tests/test_server.py index c650be290..50b82749f 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -91,3 +91,9 @@ async def test_request_than_limit_max_requests_warn_log( responses = await asyncio.gather(*tasks) assert len(responses) == 2 assert "Maximum request limit of 1 exceeded. Terminating process." in caplog.text + + +async def test_log_messages_for_all_addresses(unused_tcp_port: int, caplog: pytest.LogCaptureFixture): + config = Config(app=app, host="0.0.0.0", port=unused_tcp_port) + async with run_server(config): + assert f"Running on http://127.0.0.1:{unused_tcp_port}" in caplog.text