diff --git a/.readthedocs.yml b/.readthedocs.yml index b3edaf4b8ea..b7d8a9236f6 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,6 +5,10 @@ --- version: 2 +sphinx: + # Path to your Sphinx configuration file. + configuration: docs/conf.py + submodules: include: all exclude: [] diff --git a/CHANGES/10332.feature.rst b/CHANGES/10332.feature.rst new file mode 100644 index 00000000000..e5c84adf50d --- /dev/null +++ b/CHANGES/10332.feature.rst @@ -0,0 +1 @@ +Improved logging of HTTP protocol errors to include the remote address -- by :user:`bdraco`. diff --git a/aiohttp/web_protocol.py b/aiohttp/web_protocol.py index 3d76fc1f1d7..613ef91d65e 100644 --- a/aiohttp/web_protocol.py +++ b/aiohttp/web_protocol.py @@ -719,9 +719,13 @@ def handle_error( # or encrypted traffic to an HTTP port. This is expected # to happen when connected to the public internet so we log # it at the debug level as to not fill logs with noise. - self.logger.debug("Error handling request", exc_info=exc) + self.logger.debug( + "Error handling request from %s", request.remote, exc_info=exc + ) else: - self.log_exception("Error handling request", exc_info=exc) + self.log_exception( + "Error handling request from %s", request.remote, exc_info=exc + ) # some data already got sent, connection is broken if request.writer.output_size > 0: diff --git a/requirements/constraints.txt b/requirements/constraints.txt index db15ec605ad..5a651d8e5bf 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -39,7 +39,7 @@ cfgv==3.4.0 # via pre-commit charset-normalizer==3.4.1 # via requests -cherry-picker==2.4.0 +cherry-picker==2.5.0 # via -r requirements/dev.in click==8.1.8 # via @@ -182,7 +182,7 @@ pytest-xdist==3.6.1 # via -r requirements/test.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.74.0 +python-on-whales==0.75.1 # via # -r requirements/lint.in # -r requirements/test.in @@ -224,6 +224,10 @@ sphinxcontrib-spelling==8.0.1 ; platform_system != "Windows" # via -r requirements/doc-spelling.in sphinxcontrib-towncrier==0.4.0a0 # via -r requirements/doc.in +stamina==24.3.0 + # via cherry-picker +tenacity==9.0.0 + # via stamina tomli==2.2.1 # via # build @@ -262,7 +266,7 @@ uvloop==0.21.0 ; platform_system != "Windows" # -r requirements/lint.in valkey==6.0.2 # via -r requirements/lint.in -virtualenv==20.29.0 +virtualenv==20.29.1 # via pre-commit wait-for-it==2.3.0 # via -r requirements/test.in diff --git a/requirements/dev.txt b/requirements/dev.txt index 9b4cce59834..5282e688d2a 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -39,7 +39,7 @@ cfgv==3.4.0 # via pre-commit charset-normalizer==3.4.1 # via requests -cherry-picker==2.4.0 +cherry-picker==2.5.0 # via -r requirements/dev.in click==8.1.8 # via @@ -177,7 +177,7 @@ pytest-xdist==3.6.1 # via -r requirements/test.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.74.0 +python-on-whales==0.75.1 # via # -r requirements/lint.in # -r requirements/test.in @@ -215,6 +215,10 @@ sphinxcontrib-serializinghtml==2.0.0 # via sphinx sphinxcontrib-towncrier==0.4.0a0 # via -r requirements/doc.in +stamina==24.3.0 + # via cherry-picker +tenacity==9.0.0 + # via stamina tomli==2.2.1 # via # build @@ -253,7 +257,7 @@ uvloop==0.21.0 ; platform_system != "Windows" and implementation_name == "cpytho # -r requirements/lint.in valkey==6.0.2 # via -r requirements/lint.in -virtualenv==20.29.0 +virtualenv==20.29.1 # via pre-commit wait-for-it==2.3.0 # via -r requirements/test.in diff --git a/requirements/lint.txt b/requirements/lint.txt index 1528afe9d0a..9e4603ed7a2 100644 --- a/requirements/lint.txt +++ b/requirements/lint.txt @@ -76,7 +76,7 @@ pytest-mock==3.14.0 # via -r requirements/lint.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.74.0 +python-on-whales==0.75.1 # via -r requirements/lint.in pyyaml==6.0.2 # via pre-commit @@ -104,5 +104,5 @@ uvloop==0.21.0 ; platform_system != "Windows" # via -r requirements/lint.in valkey==6.0.2 # via -r requirements/lint.in -virtualenv==20.29.0 +virtualenv==20.29.1 # via pre-commit diff --git a/requirements/test.txt b/requirements/test.txt index fe533c13c36..5c87bae49b0 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -98,7 +98,7 @@ pytest-xdist==3.6.1 # via -r requirements/test.in python-dateutil==2.9.0.post0 # via freezegun -python-on-whales==0.74.0 +python-on-whales==0.75.1 # via -r requirements/test.in rich==13.9.4 # via pytest-codspeed diff --git a/tests/test_imports.py b/tests/test_imports.py index bfcdde3311f..1579135d539 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -38,7 +38,7 @@ def test_web___all__(pytester: pytest.Pytester) -> None: # and even slower under pytest-xdist, especially in CI _XDIST_WORKER_COUNT * 100 * (1 if _IS_CI_ENV else 1.53) if _IS_XDIST_RUN - else 265 + else 295 ), } _TARGET_TIMINGS_BY_PYTHON_VERSION["3.13"] = _TARGET_TIMINGS_BY_PYTHON_VERSION["3.12"] diff --git a/tests/test_web_server.py b/tests/test_web_server.py index 12e72b865da..c4a45f732be 100644 --- a/tests/test_web_server.py +++ b/tests/test_web_server.py @@ -67,7 +67,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: assert txt.startswith("500 Internal Server Error") assert "Traceback" not in txt - logger.exception.assert_called_with("Error handling request", exc_info=exc) + logger.exception.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_logs_invalid_method_with_loop_debug( @@ -96,7 +98,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: # on the first request since the client may # be probing for TLS/SSL support which is # expected to fail - logger.debug.assert_called_with("Error handling request", exc_info=exc) + logger.debug.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) logger.debug.reset_mock() # Now make another connection to the server @@ -110,7 +114,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: # on the first request since the client may # be probing for TLS/SSL support which is # expected to fail - logger.debug.assert_called_with("Error handling request", exc_info=exc) + logger.debug.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_logs_invalid_method_without_loop_debug( @@ -139,7 +145,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: # on the first request since the client may # be probing for TLS/SSL support which is # expected to fail - logger.debug.assert_called_with("Error handling request", exc_info=exc) + logger.debug.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_logs_invalid_method_second_request( @@ -170,7 +178,9 @@ async def handler(request: web.BaseRequest) -> web.Response: # BadHttpMethod should be logged as an exception # if its not the first request since we know # that the client already was speaking HTTP - logger.exception.assert_called_with("Error handling request", exc_info=exc) + logger.exception.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_logs_bad_status_line_as_exception( @@ -195,7 +205,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: txt = await resp.text() assert "Traceback (most recent call last):\n" not in txt - logger.exception.assert_called_with("Error handling request", exc_info=exc) + logger.exception.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_handler_timeout( @@ -280,7 +292,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: txt = await resp.text() assert "Traceback (most recent call last):\n" in txt - logger.exception.assert_called_with("Error handling request", exc_info=exc) + logger.exception.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_html_exception( @@ -311,7 +325,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: "\n" ) - logger.exception.assert_called_with("Error handling request", exc_info=exc) + logger.exception.assert_called_with( + "Error handling request from %s", cli.host, exc_info=exc + ) async def test_raw_server_html_exception_debug( @@ -339,7 +355,9 @@ async def handler(request: web.BaseRequest) -> NoReturn: "
Traceback (most recent call last):\n"
     )
 
-    logger.exception.assert_called_with("Error handling request", exc_info=exc)
+    logger.exception.assert_called_with(
+        "Error handling request from %s", cli.host, exc_info=exc
+    )
 
 
 async def test_handler_cancellation(unused_port_socket: socket.socket) -> None: