diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index fbe914a26f0..c910664f15e 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -912,5 +912,18 @@ class LiteLLM_SpendLogs(LiteLLMBase): request_tags: Optional[Json] = None +class LiteLLM_ErrorLogs(LiteLLMBase): + request_id: Optional[str] = str(uuid.uuid4()) + api_base: Optional[str] = "" + model_group: Optional[str] = "" + model_id: Optional[str] = "" + request_kwargs: Optional[dict] = {} + exception_type: Optional[str] = "" + status_code: Optional[str] = "" + exception_string: Optional[str] = "" + startTime: Union[str, datetime, None] + endTime: Union[str, datetime, None] + + class LiteLLM_SpendLogs_ResponseObject(LiteLLMBase): response: Optional[List[Union[LiteLLM_SpendLogs, Any]]] = None diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 29f3c41dba9..3a7821d2727 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -1217,6 +1217,67 @@ def cost_tracking(): litellm.success_callback.append(_PROXY_track_cost_callback) # type: ignore +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 +): + global prisma_client + 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: + # 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)[:500] + + error_log = LiteLLM_ErrorLogs( + request_id=str(uuid.uuid4()), + model_group=_model_group, + model_id=_model_id, + 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"), + ) + + # helper function to convert to dict on pydantic v2 & v1 + error_log_dict = _get_pydantic_json_dict(error_log) + 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 + + async def _PROXY_track_cost_callback( kwargs, # kwargs to completion completion_response: litellm.ModelResponse, # response from completion @@ -1302,6 +1363,15 @@ async def _PROXY_track_cost_callback( verbose_proxy_logger.debug("error in tracking cost callback - %s", e) +def error_tracking(): + global prisma_client, custom_db_client + if prisma_client is not None or custom_db_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.failure_callback.append(_PROXY_failure_handler) # type: ignore + + def _set_spend_logs_payload( payload: dict, prisma_client: PrismaClient, spend_logs_url: Optional[str] = None ): @@ -3194,6 +3264,9 @@ async def startup_event(): ## COST TRACKING ## cost_tracking() + ## Error Tracking ## + error_tracking() + db_writer_client = HTTPHandler() proxy_logging_obj._init_litellm_callbacks() # INITIALIZE LITELLM CALLBACKS ON SERVER STARTUP <- do this to catch any logging errors on startup, not when calls are being made diff --git a/schema.prisma b/schema.prisma index 5ec73c9dc16..b362a0ec025 100644 --- a/schema.prisma +++ b/schema.prisma @@ -183,6 +183,20 @@ model LiteLLM_SpendLogs { end_user String? } +// View spend, model, api_key per request +model LiteLLM_ErrorLogs { + request_id String @id @default(uuid()) + startTime DateTime // Assuming start_time is a DateTime field + endTime DateTime // Assuming end_time is a DateTime field + api_base String @default("") + model_group String @default("") // public model_name / model_group + model_id String @default("") // ID of model in ProxyModelTable + request_kwargs Json @default("{}") + exception_type String @default("") + exception_string String @default("") + status_code String @default("") +} + // Beta - allow team members to request access to a model model LiteLLM_UserNotifications { request_id String @id