o
    ưi22                     @   s   d Z ddlZddlZddlmZmZmZ ddlmZmZm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZmZmZmZ ddlmZmZmZ dZdZ dZ!dZ"G dd deZ#dS )a\  
PagerDuty Alerting Integration

Handles two types of alerts:
- High LLM API Failure Rate. Configure X fails in Y seconds to trigger an alert.
- High Number of Hanging LLM Requests. Configure X hangs in Y seconds to trigger an alert.

Note: This is a Free feature on the regular litellm docker image.

However, this is under the enterprise license
    N)datetime	timedeltatimezone)ListOptionalUnion)verbose_logger)	DualCache)SlackAlerting)AsyncHTTPHandlerget_async_httpx_clienthttpxSpecialProvider)UserAPIKeyAuth)AlertingConfigPagerDutyInternalEventPagerDutyPayloadPagerDutyRequestBody)CallTypesLiteralStandardLoggingPayload&StandardLoggingPayloadErrorInformation<   iX  c                       s   e Zd ZdZ	d deeeef  f fddZdd Z	de
d	ed
ededeeeeef  f
ddZdee de
fddZdee dededefddZ	d!dee dedee fddZdedefddZ  ZS )"PagerDutyAlertingz
    Tracks failed requests and hanging requests separately.
    If threshold is crossed for either type, triggers a PagerDuty alert.
    Nalerting_argsc                    sp   t    td}|std|| _|pi }t|dt|dt	|dt
|dtd| _g | _g | _d S )NZPAGERDUTY_API_KEYzPAGERDUTY_API_KEY is not setfailure_threshold failure_threshold_window_secondshanging_threshold_seconds hanging_threshold_window_seconds)r   r   r   r   )super__init__osgetenv
ValueErrorapi_keyr   get#PAGERDUTY_DEFAULT_FAILURE_THRESHOLD2PAGERDUTY_DEFAULT_FAILURE_THRESHOLD_WINDOW_SECONDS+PAGERDUTY_DEFAULT_HANGING_THRESHOLD_SECONDS2PAGERDUTY_DEFAULT_HANGING_THRESHOLD_WINDOW_SECONDSpagerduty_alerting_args_failure_events_hanging_events)selfr   kwargsZ_api_key	__class__ r/home/app/Keep/.python/lib/python3.10/site-packages/litellm_enterprise/enterprise_callbacks/pagerduty/pagerduty.pyr   3   s0   


zPagerDutyAlerting.__init__c              	      sd  t tj}|d}|std|dpi }|dpi }| jtd!i ddd|d|dd	|d	d
|dd|dd|dd|dd|dd|dd|dd|dd|dd|dd|dd|dd|dd|dd|d | j	dd}	| j	dd}
| j
| j|	|
ddI d H  d S )"z
        Record a failure event. Only send an alert to PagerDuty if the
        configured *failure* threshold is exceeded in the specified window.
        Zstandard_logging_objectz9standard_logging_object is required for PagerDutyAlertingZerror_informationmetadatafailure_event_typeZfailed_response	timestamperror_class
error_codeerror_llm_providerllm_provideruser_api_key_hashuser_api_key_aliasuser_api_key_spenduser_api_key_max_budgetuser_api_key_budget_reset_atuser_api_key_org_iduser_api_key_team_iduser_api_key_project_iduser_api_key_user_iduser_api_key_team_aliasuser_api_key_end_user_iduser_api_key_user_emailuser_api_key_request_routeuser_api_key_auth_metadatar   r   r      zHigh LLM API Failure Rateeventswindow_seconds	thresholdalert_prefixNr/   )r   nowr   utcr#   r!   r)   appendr   r(   !_send_alert_if_thresholds_crossed)r+   r,   Zresponse_obj
start_timeend_timerL   Zstandard_logging_payload
error_info_metarI   rJ   r/   r/   r0   async_log_failure_eventT   s~   






	










z)PagerDutyAlerting.async_log_failure_eventuser_api_key_dictcachedata	call_typereturnc                    s$   t d t| j||d dS )z
        Example of detecting hanging requests by waiting a given threshold.
        If the request didn't finish by then, we treat it as 'hanging'.
        z#Inside Proxy Logging Pre-call hook!)request_datarU   N)r   infoasynciocreate_taskhanging_response_handler)r+   rU   rV   rW   rX   r/   r/   r0   async_pre_call_hook   s   
z%PagerDutyAlerting.async_pre_call_hookrZ   c              	      s  t d| jdt d t| jdtI dH  | j|dI dH r'dS | j	t
di dddttjd	d
dd
dd
d|jd|jd|jd|jd|jrY|j nFdd|jd|jd|jd|jd|jd|jd|jd|jd|j | jdt}| jdt}| j| j||ddI dH  dS d|jd|jd|jd|jd|jd|jd|jd|jd|j | jdt}| jdt}| j| j||ddI dH  dS ) z
        Checks if request completed by the time 'hanging_threshold_seconds' elapses.
        If not, we classify it as a hanging request.
        z/Inside Hanging Response Handler!..sleeping for r   z secondsN)rZ   r2   Zhanging_responser3   r4   ZHangingRequestr5   r6   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   r   Zhanging_threshold_failsz#High Number of Hanging LLM RequestsrG   r/   ) r   debugr(   r#   r&   r\   sleepZ_request_is_completedr*   rN   r   r   rL   r   rM   r"   Z	key_aliasZspendZ
max_budgetZbudget_reset_at	isoformatZorg_idZteam_idZ
project_idZuser_idZ
team_aliasZend_user_idZ
user_emailZrequest_router1   r'   rO   )r+   rZ   rU   rI   rJ   r/   r/   r0   r^      s   
	z*PagerDutyAlerting.hanging_response_handlerrH   rI   rJ   rK   c           	         s   t tjt|d   fdd|D }|  || tdt	| d| d|  t	||kr\| j
|dd}| d	t	| d
| d}d|i}| j||dI dH  |  dS dS )z
        1. Prune old events
        2. If threshold is reached, build alert, send to PagerDuty
        3. Clear those events
        )secondsc                    s"   g | ]}| d tj kr|qS )r3   )r#   r   min).0ecutoffr/   r0   
<listcomp>   s   " zGPagerDutyAlerting._send_alert_if_thresholds_crossed.<locals>.<listcomp>zHave z events in the last z seconds. Threshold is    )
max_errorsz: z in the last z	 seconds.Zrecent_errors)alert_messagecustom_detailsN)r   rL   r   rM   r   clearextendr   r`   len_build_error_summariessend_alert_to_pagerduty)	r+   rH   rI   rJ   rK   ZprunedZerror_summariesrl   rm   r/   rg   r0   rO      s&   
z3PagerDutyAlerting._send_alert_if_thresholds_crossedrj   rk   c                 C   s4   || d }g }|D ]}| d || q|S )z
        Build short text summaries for the last `max_errors`.
        Example: "ValueError (code: 500, provider: openai)"
        Nr3   )poprN   )r+   rH   rk   ZrecentZ	summariesZfer/   r/   r0   rq     s   
z(PagerDutyAlerting._build_error_summariesrl   rm   c              
      s   z-t d|  ttjd}tt|ddd|d| jdd}|jd	t	|d
didI dH W S  t
yI } zt d|  W Y d}~dS d}~ww )z
        Send [critical] Alert to PagerDuty

        https://developer.pagerduty.com/api-reference/YXBpOjI3NDgyNjU-pager-duty-v2-events-api
        zSending alert to PagerDuty: )r7   criticalzLiteLLM AlertZLiteLLM)summaryZseveritysource	componentrm   trigger)payloadZrouting_keyZevent_actionz'https://events.pagerduty.com/v2/enqueuezContent-Typezapplication/json)urljsonheadersNz"Error sending alert to PagerDuty: )r   r`   r   r   ZLoggingCallbackr   r   r"   postdict	Exception	exception)r+   rl   rm   Zasync_clientry   rf   r/   r/   r0   rr     s4   z)PagerDutyAlerting.send_alert_to_pagerduty)N)rj   )__name__
__module____qualname____doc__r   r   r   r~   r   rT   r   r	   r   r   strr_   r^   r   r   intrO   rq   rr   __classcell__r/   r/   r-   r0   r   -   sR    !:

C
(
r   )$r   r\   r   r   r   r   typingr   r   r   Zlitellm._loggingr   Zlitellm.cachingr	   Z1litellm.integrations.SlackAlerting.slack_alertingr
   Z&litellm.llms.custom_httpx.http_handlerr   r   r   Zlitellm.proxy._typesr   Z$litellm.types.integrations.pagerdutyr   r   r   r   Zlitellm.types.utilsr   r   r   r$   r%   r&   r'   r   r/   r/   r/   r0   <module>   s"    