(Clean up) - Allow switching off storing Error Logs in DB (#9084)

* fix - cleanup, dont store ErrorLogs in 2 tables

* async_post_call_failure_hook

* docs disable error logs

* disable_error_logs
This commit is contained in:
Ishaan Jaff 2025-03-08 16:12:03 -08:00 • committed by GitHub
parent a7f6a95dd9
commit 73df319f4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 23 additions and 180 deletions

View file

@ -46,18 +46,17 @@ You can see the full DB Schema [here](https://github.com/BerriAI/litellm/blob/ma
| Table Name | Description | Row Insert Frequency |
|------------|-------------|---------------------|
| LiteLLM_SpendLogs | Detailed logs of all API requests. Records token usage, spend, and timing information. Tracks which models and keys were used. | **High - every LLM API request** |
| LiteLLM_ErrorLogs | Captures failed requests and errors. Stores exception details and request information. Helps with debugging and monitoring. | **Medium - on errors only** |
| LiteLLM_SpendLogs | Detailed logs of all API requests. Records token usage, spend, and timing information. Tracks which models and keys were used. | **High - every LLM API request - Success or Failure** |
| LiteLLM_AuditLog | Tracks changes to system configuration. Records who made changes and what was modified. Maintains history of updates to teams, users, and models. | **Off by default**, **High - when enabled** |
## Disable `LiteLLM_SpendLogs` & `LiteLLM_ErrorLogs`
## Disable `LiteLLM_SpendLogs`
You can disable spend_logs and error_logs by setting `disable_spend_logs` and `disable_error_logs` to `True` on the `general_settings` section of your proxy_config.yaml file.
```yaml
general_settings:
disable_spend_logs: True # Disable writing spend logs to DB
disable_error_logs: True # Disable writing error logs to DB
disable_error_logs: True # Only disable writing error logs to DB, regular spend logs will still be written unless `disable_spend_logs: True`
```
### What is the impact of disabling these logs?

View file

@ -107,9 +107,9 @@ general_settings:
By default, LiteLLM writes several types of logs to the database:
- Every LLM API request to the `LiteLLM_SpendLogs` table
- LLM Exceptions to the `LiteLLM_LogsErrors` table
- LLM Exceptions to the `LiteLLM_SpendLogs` table
If you're not viewing these logs on the LiteLLM UI (most users use Prometheus for monitoring), you can disable them by setting the following flags to `True`:
If you're not viewing these logs on the LiteLLM UI, you can disable them by setting the following flags to `True`:
```yaml
general_settings:

View file

@ -1,87 +0,0 @@
"""
Runs when LLM Exceptions occur on LiteLLM Proxy
"""
import copy
import json
import uuid
import litellm
from litellm.proxy._types import LiteLLM_ErrorLogs
async def _PROXY_failure_handler(
kwargs, # kwargs to completion
completion_response: litellm.ModelResponse, # response from completion
start_time=None,
end_time=None, # start/end time for completion
):
"""
Async Failure Handler - runs when LLM Exceptions occur on LiteLLM Proxy.
This function logs the errors to the Prisma DB
Can be disabled by setting the following on proxy_config.yaml:
```yaml
general_settings:
disable_error_logs: True
```
"""
from litellm._logging import verbose_proxy_logger
from litellm.proxy.proxy_server import general_settings, prisma_client
if general_settings.get("disable_error_logs") is True:
return
if prisma_client is not None:
verbose_proxy_logger.debug(
"inside _PROXY_failure_handler kwargs=", extra=kwargs
)
_exception = kwargs.get("exception")
_exception_type = _exception.__class__.__name__
_model = kwargs.get("model", None)
_optional_params = kwargs.get("optional_params", {})
_optional_params = copy.deepcopy(_optional_params)
for k, v in _optional_params.items():
v = str(v)
v = v[:100]
_status_code = "500"
try:
_status_code = str(_exception.status_code)
except Exception:
# Don't let this fail logging the exception to the dB
pass
_litellm_params = kwargs.get("litellm_params", {}) or {}
_metadata = _litellm_params.get("metadata", {}) or {}
_model_id = _metadata.get("model_info", {}).get("id", "")
_model_group = _metadata.get("model_group", "")
api_base = litellm.get_api_base(model=_model, optional_params=_litellm_params)
_exception_string = str(_exception)
error_log = LiteLLM_ErrorLogs(
request_id=str(uuid.uuid4()),
model_group=_model_group,
model_id=_model_id,
litellm_model_name=kwargs.get("model"),
request_kwargs=_optional_params,
api_base=api_base,
exception_type=_exception_type,
status_code=_status_code,
exception_string=_exception_string,
startTime=kwargs.get("start_time"),
endTime=kwargs.get("end_time"),
)
error_log_dict = error_log.model_dump()
error_log_dict["request_kwargs"] = json.dumps(error_log_dict["request_kwargs"])
await prisma_client.db.litellm_errorlogs.create(
data=error_log_dict # type: ignore
)
pass

View file

@ -34,6 +34,9 @@ class _ProxyDBLogger(CustomLogger):
):
from litellm.proxy.proxy_server import update_database
if _ProxyDBLogger._should_track_errors_in_db() is False:
return
_metadata = dict(
StandardLoggingUserAPIKeyMetadata(
user_api_key_hash=user_api_key_dict.api_key,
@ -202,6 +205,21 @@ class _ProxyDBLogger(CustomLogger):
"Error in tracking cost callback - %s", str(e)
)
@staticmethod
def _should_track_errors_in_db():
"""
Returns True if errors should be tracked in the database
By default, errors are tracked in the database
If users want to disable error tracking, they can set the disable_error_logs flag in the general_settings
"""
from litellm.proxy.proxy_server import general_settings
if general_settings.get("disable_error_logs") is True:
return False
return
def _should_track_cost_callback(
user_api_key: Optional[str],

View file

@ -179,7 +179,6 @@ from litellm.proxy.hooks.model_max_budget_limiter import (
from litellm.proxy.hooks.prompt_injection_detection import (
_OPTIONAL_PromptInjectionDetection,
)
from litellm.proxy.hooks.proxy_failure_handler import _PROXY_failure_handler
from litellm.proxy.hooks.proxy_track_cost_callback import _ProxyDBLogger
from litellm.proxy.litellm_pre_call_utils import add_litellm_data_to_request
from litellm.proxy.management_endpoints.budget_management_endpoints import (
@ -942,15 +941,6 @@ def cost_tracking():
litellm.logging_callback_manager.add_litellm_callback(_ProxyDBLogger())
def error_tracking():
global prisma_client
if prisma_client is not None:
if isinstance(litellm.failure_callback, list):
verbose_proxy_logger.debug("setting litellm failure callback to track cost")
if (_PROXY_failure_handler) not in litellm.failure_callback: # type: ignore
litellm.logging_callback_manager.add_litellm_failure_callback(_PROXY_failure_handler) # type: ignore
def _set_spend_logs_payload(
payload: Union[dict, SpendLogsPayload],
prisma_client: PrismaClient,
@ -3150,9 +3140,6 @@ class ProxyStartupEvent:
## COST TRACKING ##
cost_tracking()
## Error Tracking ##
error_tracking()
proxy_logging_obj.startup_event(
llm_router=llm_router, redis_usage_cache=redis_usage_cache
)

View file

@ -10,43 +10,6 @@ sys.path.insert(0, os.path.abspath("../.."))
import litellm
@pytest.mark.asyncio
async def test_disable_error_logs():
"""
Test that the error logs are not written to the database when disable_error_logs is True
"""
# Mock the necessary components
mock_prisma_client = AsyncMock()
mock_general_settings = {"disable_error_logs": True}
with patch(
"litellm.proxy.proxy_server.general_settings", mock_general_settings
), patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client):
# Create a test exception
test_exception = Exception("Test error")
test_kwargs = {
"model": "gpt-4",
"exception": test_exception,
"optional_params": {},
"litellm_params": {"metadata": {}},
}
# Call the failure handler
from litellm.proxy.proxy_server import _PROXY_failure_handler
await _PROXY_failure_handler(
kwargs=test_kwargs,
completion_response=None,
start_time="2024-01-01",
end_time="2024-01-01",
)
# Verify prisma client was not called to create error logs
if hasattr(mock_prisma_client, "db"):
assert not mock_prisma_client.db.litellm_errorlogs.create.called
@pytest.mark.asyncio
async def test_disable_spend_logs():
"""
@ -72,40 +35,3 @@ async def test_disable_spend_logs():
)
# Verify no spend logs were added
assert len(mock_prisma_client.spend_log_transactions) == 0
@pytest.mark.asyncio
async def test_enable_error_logs():
"""
Test that the error logs are written to the database when disable_error_logs is False
"""
# Mock the necessary components
mock_prisma_client = AsyncMock()
mock_general_settings = {"disable_error_logs": False}
with patch(
"litellm.proxy.proxy_server.general_settings", mock_general_settings
), patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client):
# Create a test exception
test_exception = Exception("Test error")
test_kwargs = {
"model": "gpt-4",
"exception": test_exception,
"optional_params": {},
"litellm_params": {"metadata": {}},
}
# Call the failure handler
from litellm.proxy.proxy_server import _PROXY_failure_handler
await _PROXY_failure_handler(
kwargs=test_kwargs,
completion_response=None,
start_time="2024-01-01",
end_time="2024-01-01",
)
# Verify prisma client was called to create error logs
if hasattr(mock_prisma_client, "db"):
assert mock_prisma_client.db.litellm_errorlogs.create.called