Enhance Akto health check logging and add tests for failure scenarios

This commit is contained in:
rzeta-10 2026-03-23 15:15:30 +05:30
parent 09037162a9
commit 5d5b530d8d
2 changed files with 91 additions and 2 deletions

View file

@ -348,7 +348,8 @@ async def health_services_endpoint( # noqa: PLR0915
akto_logger = _akto if _akto is not None else AktoLogger()
response = await akto_logger.async_health_check()
except Exception as e:
return {"status": "unhealthy", "error_message": str(e)}
verbose_proxy_logger.warning("Akto health check error: %s", e)
return {"status": "unhealthy", "error_message": "Akto health check failed"}
return {
"status": response["status"],
"message": (

View file

@ -218,11 +218,85 @@ async def test_async_log_failure_event(logger, sample_kwargs):
assert payload["statusCode"] == "500"
# ── Async failure with response_obj ──
@pytest.mark.asyncio
async def test_async_log_failure_with_response_obj(logger, sample_kwargs):
logger.async_http_handler.post = AsyncMock(return_value=MagicMock(status_code=200))
mock_resp = MagicMock()
mock_resp.model_dump.return_value = {"partial": "data"}
await logger.async_log_failure_event(
kwargs=sample_kwargs, response_obj=mock_resp, start_time=None, end_time=None
)
payload = json.loads(logger.async_http_handler.post.call_args.kwargs["data"])
assert payload["statusCode"] == "500"
assert json.loads(payload["responsePayload"])["partial"] == "data"
@pytest.mark.asyncio
async def test_async_log_failure_with_status_code(logger, sample_kwargs):
logger.async_http_handler.post = AsyncMock(return_value=MagicMock(status_code=200))
exc = MagicMock()
exc.status_code = 403
sample_kwargs["exception"] = exc
await logger.async_log_failure_event(
kwargs=sample_kwargs, response_obj=None, start_time=None, end_time=None
)
payload = json.loads(logger.async_http_handler.post.call_args.kwargs["data"])
assert payload["statusCode"] == "403"
# ── Client IP extraction ──
def test_extract_client_ip_forwarded():
assert AktoLogger.extract_client_ip(
{"proxy_server_request": {"headers": {"x-forwarded-for": "1.2.3.4, 5.6.7.8"}}}
) == "1.2.3.4"
def test_extract_client_ip_real_ip():
assert AktoLogger.extract_client_ip(
{"proxy_server_request": {"headers": {"x-real-ip": "10.0.0.1"}}}
) == "10.0.0.1"
def test_extract_client_ip_fallback():
assert AktoLogger.extract_client_ip({}) == "0.0.0.0"
# ── Request path extraction ──
def test_extract_request_path_from_metadata():
assert AktoLogger.extract_request_path(
{"metadata": {"user_api_key_request_route": "/v1/embeddings"}}
) == "/v1/embeddings"
def test_extract_request_path_fallback():
assert AktoLogger.extract_request_path({}) == "/v1/chat/completions"
# ── Default host fallback ──
def test_build_request_headers_default_host():
headers = AktoLogger.build_request_headers({})
assert headers["host"] == "litellm.ai"
assert headers["content-type"] == "application/json"
# ── Error handling ──
@pytest.mark.asyncio
async def test_async_log_swallows_errors(logger):
async def test_async_log_success_swallows_errors(logger):
logger.async_http_handler.post = AsyncMock(
side_effect=httpx.ConnectError("refused")
)
@ -233,3 +307,17 @@ async def test_async_log_swallows_errors(logger):
start_time=None,
end_time=None,
)
@pytest.mark.asyncio
async def test_async_log_failure_swallows_errors(logger):
logger.async_http_handler.post = AsyncMock(
side_effect=httpx.ConnectError("refused")
)
# Should not raise
await logger.async_log_failure_event(
kwargs={"messages": [], "model": "m", "litellm_params": {}},
response_obj=None,
start_time=None,
end_time=None,
)