Improve error logging of WebSocket API (#81360)

This commit is contained in:
Franck Nijhof 2022-11-01 19:11:50 +01:00 committed by GitHub
parent b4637fae37
commit 5c99e2e5d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 22 deletions

View file

@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any
import voluptuous as vol import voluptuous as vol
from homeassistant.auth.models import RefreshToken, User from homeassistant.auth.models import RefreshToken, User
from homeassistant.components.http import current_request
from homeassistant.core import Context, HomeAssistant, callback from homeassistant.core import Context, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError, Unauthorized from homeassistant.exceptions import HomeAssistantError, Unauthorized
@ -137,6 +138,13 @@ class ActiveConnection:
err_message = "Unknown error" err_message = "Unknown error"
log_handler = self.logger.exception log_handler = self.logger.exception
log_handler("Error handling message: %s (%s)", err_message, code)
self.send_message(messages.error_message(msg["id"], code, err_message)) self.send_message(messages.error_message(msg["id"], code, err_message))
if code:
err_message += f" ({code})"
if request := current_request.get():
err_message += f" from {request.remote}"
if user_agent := request.headers.get("user-agent"):
err_message += f" ({user_agent})"
log_handler("Error handling message: %s", err_message)

View file

@ -1,8 +1,11 @@
"""Test WebSocket Connection class.""" """Test WebSocket Connection class."""
import asyncio import asyncio
import logging import logging
from unittest.mock import Mock from typing import Any
from unittest.mock import AsyncMock, Mock, patch
from aiohttp.test_utils import make_mocked_request
import pytest
import voluptuous as vol import voluptuous as vol
from homeassistant import exceptions from homeassistant import exceptions
@ -11,37 +14,86 @@ from homeassistant.components import websocket_api
from tests.common import MockUser from tests.common import MockUser
async def test_exception_handling(): @pytest.mark.parametrize(
"""Test handling of exceptions.""" "exc,code,err,log",
send_messages = [] [
user = MockUser() (
refresh_token = Mock() exceptions.Unauthorized(),
conn = websocket_api.ActiveConnection( websocket_api.ERR_UNAUTHORIZED,
logging.getLogger(__name__), None, send_messages.append, user, refresh_token "Unauthorized",
) "Error handling message: Unauthorized (unauthorized) from 127.0.0.42 (Browser)",
),
for (exc, code, err) in (
(exceptions.Unauthorized(), websocket_api.ERR_UNAUTHORIZED, "Unauthorized"),
( (
vol.Invalid("Invalid something"), vol.Invalid("Invalid something"),
websocket_api.ERR_INVALID_FORMAT, websocket_api.ERR_INVALID_FORMAT,
"Invalid something. Got {'id': 5}", "Invalid something. Got {'id': 5}",
"Error handling message: Invalid something. Got {'id': 5} (invalid_format) from 127.0.0.42 (Browser)",
),
(
asyncio.TimeoutError(),
websocket_api.ERR_TIMEOUT,
"Timeout",
"Error handling message: Timeout (timeout) from 127.0.0.42 (Browser)",
), ),
(asyncio.TimeoutError(), websocket_api.ERR_TIMEOUT, "Timeout"),
( (
exceptions.HomeAssistantError("Failed to do X"), exceptions.HomeAssistantError("Failed to do X"),
websocket_api.ERR_UNKNOWN_ERROR, websocket_api.ERR_UNKNOWN_ERROR,
"Failed to do X", "Failed to do X",
"Error handling message: Failed to do X (unknown_error) from 127.0.0.42 (Browser)",
), ),
(ValueError("Really bad"), websocket_api.ERR_UNKNOWN_ERROR, "Unknown error"),
( (
exceptions.HomeAssistantError(), ValueError("Really bad"),
websocket_api.ERR_UNKNOWN_ERROR, websocket_api.ERR_UNKNOWN_ERROR,
"Unknown error", "Unknown error",
"Error handling message: Unknown error (unknown_error) from 127.0.0.42 (Browser)",
), ),
): (
send_messages.clear() exceptions.HomeAssistantError,
websocket_api.ERR_UNKNOWN_ERROR,
"Unknown error",
"Error handling message: Unknown error (unknown_error) from 127.0.0.42 (Browser)",
),
],
)
async def test_exception_handling(
caplog: pytest.LogCaptureFixture,
exc: Exception,
code: str,
err: str,
log: str,
):
"""Test handling of exceptions."""
send_messages = []
user = MockUser()
refresh_token = Mock()
current_request = AsyncMock()
def get_extra_info(key: str) -> Any:
if key == "sslcontext":
return True
if key == "peername":
return ("127.0.0.42", 8123)
mocked_transport = Mock()
mocked_transport.get_extra_info = get_extra_info
mocked_request = make_mocked_request(
"GET",
"/api/websocket",
headers={"Host": "example.com", "User-Agent": "Browser"},
transport=mocked_transport,
)
with patch(
"homeassistant.components.websocket_api.connection.current_request",
) as current_request:
current_request.get.return_value = mocked_request
conn = websocket_api.ActiveConnection(
logging.getLogger(__name__), None, send_messages.append, user, refresh_token
)
conn.async_handle_exception({"id": 5}, exc) conn.async_handle_exception({"id": 5}, exc)
assert len(send_messages) == 1 assert len(send_messages) == 1
assert send_messages[0]["error"]["code"] == code assert send_messages[0]["error"]["code"] == code
assert send_messages[0]["error"]["message"] == err assert send_messages[0]["error"]["message"] == err
assert log in caplog.text