mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
feat(spend-logs): suppress traceback in SpendLogs error_information row
Some checks are pending
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Some checks are pending
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Extend LITELLM_SUPPRESS_SPEND_LOG_TRACEBACKS to the failure callback so the per-row Metadata pane in the UI no longer shows the stack trace when the opt-in env var is set, matching the existing console-side suppression. https://claude.ai/code/session_014dztoRbRnRvq54HL9EyHx6
This commit is contained in:
parent
dfd8c406ee
commit
5b775d1274
3 changed files with 101 additions and 17 deletions
|
|
@ -19,7 +19,10 @@ from litellm.proxy.auth.auth_checks import (
|
|||
)
|
||||
from litellm.proxy.auth.route_checks import RouteChecks
|
||||
from litellm.proxy.litellm_pre_call_utils import LiteLLMProxyRequestSetup
|
||||
from litellm.proxy.spend_tracking.spend_log_error_logger import spend_log_error
|
||||
from litellm.proxy.spend_tracking.spend_log_error_logger import (
|
||||
should_suppress_spend_log_tracebacks,
|
||||
spend_log_error,
|
||||
)
|
||||
from litellm.proxy.utils import ProxyUpdateSpend
|
||||
from litellm.types.utils import StandardLoggingPayload
|
||||
from litellm.utils import get_end_user_id_for_cost_tracking
|
||||
|
|
@ -75,12 +78,13 @@ class _ProxyDBLogger(CustomLogger):
|
|||
)
|
||||
_metadata["user_api_key"] = user_api_key_dict.api_key
|
||||
_metadata["status"] = "failure"
|
||||
_metadata["error_information"] = (
|
||||
StandardLoggingPayloadSetup.get_error_information(
|
||||
original_exception=original_exception,
|
||||
traceback_str=traceback_str,
|
||||
)
|
||||
_error_information = StandardLoggingPayloadSetup.get_error_information(
|
||||
original_exception=original_exception,
|
||||
traceback_str=traceback_str,
|
||||
)
|
||||
if should_suppress_spend_log_tracebacks():
|
||||
_error_information = {**_error_information, "traceback": ""}
|
||||
_metadata["error_information"] = _error_information
|
||||
|
||||
_metadata = await _ProxyDBLogger._enrich_failure_metadata_with_key_info(
|
||||
metadata=_metadata,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
"""
|
||||
Logging helpers for spend-tracking error paths.
|
||||
|
||||
Proxy operators have asked for a way to keep their downstream log sinks free of
|
||||
the stack traces that the spend-tracking machinery emits when it hits 4xx/5xx
|
||||
or transient DB errors. The errors still need to be logged (and still need to
|
||||
flow to Sentry via ``proxy_logging_obj.failure_handler``), but the multi-line
|
||||
stack traces dominate the log volume and make the surrounding INFO/ERROR lines
|
||||
hard to read.
|
||||
Proxy operators have asked for a way to keep both their downstream log sinks
|
||||
and the SpendLogs UI free of the stack traces that the spend-tracking
|
||||
machinery emits when it hits 4xx/5xx or transient DB errors. The errors still
|
||||
need to be logged (and still flow to Sentry via
|
||||
``proxy_logging_obj.failure_handler``), but the multi-line stack traces
|
||||
dominate log volume and clutter the per-row Metadata pane in the UI.
|
||||
|
||||
This module exposes ``spend_log_error`` — a thin wrapper around
|
||||
``verbose_proxy_logger.error`` that drops the traceback portion when the
|
||||
operator has opted in via ``LITELLM_SUPPRESS_SPEND_LOG_TRACEBACKS=true`` and
|
||||
the proxy logger is at INFO or above. At DEBUG the full traceback is always
|
||||
preserved.
|
||||
The opt-in is a single env var, ``LITELLM_SUPPRESS_SPEND_LOG_TRACEBACKS=true``,
|
||||
gated by ``should_suppress_spend_log_tracebacks``. When it returns ``True``:
|
||||
* ``spend_log_error`` drops the traceback from the console / structured log
|
||||
record (this module), and
|
||||
* the failure callback in ``proxy_track_cost_callback`` blanks the
|
||||
``error_information.traceback`` field on the SpendLogs row before it is
|
||||
persisted, so the UI's per-row Metadata pane stays clean.
|
||||
|
||||
At DEBUG the full traceback is always preserved so operators can still
|
||||
troubleshoot. The UI suppression follows the same gate.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
|
|
|||
|
|
@ -990,3 +990,78 @@ async def test_async_post_call_failure_hook_uses_actual_start_time():
|
|||
# Duration should be approximately 60 seconds, not 0
|
||||
duration = (call_args["end_time"] - call_args["start_time"]).total_seconds()
|
||||
assert duration >= 55, f"Duration should be ~60s, got {duration}s"
|
||||
|
||||
|
||||
async def _invoke_failure_hook_with_raised_exception():
|
||||
"""Run the failure hook with an exception that has a real ``__traceback__``.
|
||||
|
||||
Returns the metadata dict that was forwarded to ``update_database`` so the
|
||||
caller can assert on its ``error_information`` payload.
|
||||
"""
|
||||
logger = _ProxyDBLogger()
|
||||
user_api_key_dict = UserAPIKeyAuth(
|
||||
api_key="test_api_key",
|
||||
user_id="u",
|
||||
team_id="t",
|
||||
)
|
||||
request_data = {
|
||||
"model": "gpt-4",
|
||||
"messages": [{"role": "user", "content": "hi"}],
|
||||
"metadata": {},
|
||||
"proxy_server_request": {},
|
||||
}
|
||||
|
||||
try:
|
||||
raise RuntimeError("boom-with-traceback")
|
||||
except RuntimeError as exc:
|
||||
original_exception = exc
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.db.db_spend_update_writer.DBSpendUpdateWriter.update_database",
|
||||
new_callable=AsyncMock,
|
||||
) as mock_update_database:
|
||||
await logger.async_post_call_failure_hook(
|
||||
request_data=request_data,
|
||||
original_exception=original_exception,
|
||||
user_api_key_dict=user_api_key_dict,
|
||||
)
|
||||
call_args = mock_update_database.call_args[1]
|
||||
return call_args["kwargs"]["litellm_params"]["metadata"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_failure_hook_keeps_error_information_traceback_by_default(monkeypatch):
|
||||
"""Without the opt-in env var, the SpendLogs row carries the full traceback."""
|
||||
monkeypatch.delenv("LITELLM_SUPPRESS_SPEND_LOG_TRACEBACKS", raising=False)
|
||||
|
||||
metadata = await _invoke_failure_hook_with_raised_exception()
|
||||
|
||||
error_information = metadata["error_information"]
|
||||
assert error_information["error_class"] == "RuntimeError"
|
||||
assert error_information["error_message"] == "boom-with-traceback"
|
||||
assert error_information["traceback"], "expected a non-empty traceback by default"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_failure_hook_blanks_error_information_traceback_when_env_set(
|
||||
monkeypatch,
|
||||
):
|
||||
"""With the opt-in env var, the traceback in the SpendLogs row is blanked
|
||||
so the per-row Metadata pane in the UI stays clean. The other fields
|
||||
(error_class / error_message / error_code) are preserved."""
|
||||
import logging
|
||||
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
|
||||
monkeypatch.setenv("LITELLM_SUPPRESS_SPEND_LOG_TRACEBACKS", "true")
|
||||
original_level = verbose_proxy_logger.level
|
||||
verbose_proxy_logger.setLevel(logging.INFO)
|
||||
try:
|
||||
metadata = await _invoke_failure_hook_with_raised_exception()
|
||||
finally:
|
||||
verbose_proxy_logger.setLevel(original_level)
|
||||
|
||||
error_information = metadata["error_information"]
|
||||
assert error_information["traceback"] == ""
|
||||
assert error_information["error_class"] == "RuntimeError"
|
||||
assert error_information["error_message"] == "boom-with-traceback"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue