o
    ưi_o                     @   sJ  d Z ddlZddlZddlZddlZddlmZ ddlmZmZm	Z	m
Z
mZ ddlZddlmZ ddlZddlmZ ddlmZ ddlmZ dd	lmZmZ dd
lmZmZmZmZ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*m+Z+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3 e/j4gZ5G dd dee3Z6dS )ay  
DataDog Integration - sends logs to /api/v2/log

DD Reference API: https://docs.datadoghq.com/api/latest/logs

`async_log_success_event` - used by litellm proxy to send logs to datadog
`log_success_event` - sync version of logging to DataDog, only used on litellm Python SDK, if user opts in to using sync functions

async_log_success_event:  will store batch of DD_MAX_BATCH_SIZE in memory and flush to Datadog once it reaches DD_MAX_BATCH_SIZE or every 5 seconds

async_service_failure_hook: Logs failures from Redis, Postgres (Adjacent systems), as 'WARNING' on DataDog

For batching specific details see CustomBatchLogger class
    N)datetime)AnyDictListOptionalUnion)Response)verbose_logger)uuid)CustomBatchLogger)should_use_datadog_mockcreate_mock_datadog_client)get_datadog_hostnameget_datadog_serviceget_datadog_sourceget_datadog_tagsget_datadog_base_url_from_env)tracer)_get_httpx_clientget_async_httpx_clienthttpxSpecialProvider)IntegrationHealthCheckStatus)	DD_ERRORSDD_MAX_BATCH_SIZEDataDogStatusDatadogInitParamsDatadogPayload"DatadogProxyFailureHookJsonMessage)ServiceLoggerPayloadServiceTypes)StandardLoggingPayload   )AdditionalLoggingUtilsc                       s  e Zd Z fddZdefddZdeddfdd	Zd@d
dZdd Z	dd Z
	dAdedededee dee f
ddZdd Zdd Zdd ZdededefddZd eeef d!ed"ejd#ejdef
d$d%Zd&edefd'd(Z	)				dBd*ed+ee d,ee d"eeeef  d#eeeef  d-ee fd.d/Z 	)				dBd*ed+ee d,ee d"eeeef  d#eeeef  d-ee fd0d1Z!d eeef d!ed"ejd#ejdef
d2d3Z"d4eddfd5d6Z#deeeef  fd7d8Z$de%fd9d:Z&d;ed<ee d=ee dee fd>d?Z'  Z(S )CDataDogLoggerc              
      s   zct d t | _| jrt  t d |  }|| ttj	d| _
td}|r3| j|d n|   t }|rB| d| _t | _t|   t | _t jd
i || jtd W d	S  ty{ } zt dt|  |d	}~ww )a  
        Initializes the datadog logger, checks if the correct env variables are set

        Required environment variables (Direct API):
        `DD_API_KEY` - your datadog api key
        `DD_SITE` - your datadog site, example = `"us5.datadoghq.com"`

        Optional environment variables (DataDog Agent):
        `LITELLM_DD_AGENT_HOST` - hostname or IP of DataDog agent, example = `"localhost"`
        `LITELLM_DD_AGENT_PORT` - port of DataDog agent (default: 10518 for logs)

        Note: We use LITELLM_DD_AGENT_HOST instead of DD_AGENT_HOST to avoid conflicts
        with ddtrace which automatically sets DD_AGENT_HOST for APM tracing.
        zDatadog: in init datadog loggerz6[DATADOG MOCK] Datadog logger initialized in mock mode)Zllm_providerZLITELLM_DD_AGENT_HOST)dd_agent_host/api/v2/logs)
flush_lock
batch_sizez.Datadog: Got exception on init Datadog client N )r	   debugr   is_mock_moder   _get_datadog_paramsupdater   r   ZLoggingCallbackasync_clientosgetenv_configure_dd_agent_configure_dd_direct_apir   
intake_urlr   sync_clientasynciocreate_taskZperiodic_flushLockr&   super__init__r   	Exception	exceptionstr)selfkwargsdict_datadog_paramsr$   Zdd_base_urle	__class__r(   [/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/datadog/datadog.pyr8   K   sF   




zDataDogLogger.__init__returnc                 C   sL   i }t jdur$tt jtrt j }|S tt jtr$tdi t j }|S )z
        Get the datadog_params from litellm.datadog_params

        These are params specific to initializing the DataDogLogger e.g. turn_off_message_logging
        Nr(   )litellmZdatadog_params
isinstancer   
model_dumpr   )r<   r>   r(   r(   rB   r+      s   

z!DataDogLogger._get_datadog_paramsr$   Nc                 C   sB   t dd}d| d| d| _t d| _td| j  dS )	z
        Configure DataDog Agent for log forwarding

        Args:
            dd_agent_host: Hostname or IP of DataDog agent
        ZLITELLM_DD_AGENT_PORTZ10518zhttp://:r%   
DD_API_KEYzDatadog: Using DD Agent at N)r.   r/   r2   rH   r	   r)   )r<   r$   Zdd_agent_portr(   r(   rB   r0      s   z!DataDogLogger._configure_dd_agentc                 C   sT   t dddu rtdt dddu rtdt d| _dt d d| _dS )z
        Configure direct DataDog API connection

        Raises:
            Exception: If required environment variables are not set
        rH   Nz)DD_API_KEY is not set, set 'DD_API_KEY=<>ZDD_SITEz+DD_SITE is not set in .env, set 'DD_SITE=<>zhttps://http-intake.logs.r%   )r.   r/   r9   rH   r2   )r<   r(   r(   rB   r1      s   z&DataDogLogger._configure_dd_direct_apic              
      sp   zt d| | ||||I dH  W dS  ty7 } zt dt| dt   W Y d}~dS d}~ww )aF  
        Async Log success events to Datadog

        - Creates a Datadog payload
        - Adds the Payload to the in memory logs queue
        - Payload is flushed every 10 seconds or when batch size is greater than 100


        Raises:
            Raises a NON Blocking verbose_logger.exception if an error occurs
        7Datadog: Logging - Enters logging function for model %sNDatadog Layer Error - 
r	   r)   _log_async_eventr9   r:   r;   	traceback
format_excr<   r=   response_obj
start_timeend_timer?   r(   r(   rB   async_log_success_event   s   z%DataDogLogger.async_log_success_eventc              
      sp   zt d| | ||||I d H  W d S  ty7 } zt dt| dt   W Y d }~d S d }~ww )NrI   rJ   rK   rL   rP   r(   r(   rB   async_log_failure_event   s   z%DataDogLogger.async_log_failure_eventrequest_dataoriginal_exceptionuser_api_key_dicttraceback_strc              
      s  zddl m} ddlm} |j||d}|dpd}d}	|r,t|  r,t	|}	i }
zddl
m} |j|d	}t|trDt|n|}
W n= ty   t|d
r[t|d
d|
d
< t|drht|dd|
d< t|drut|dd|
d< t|drt|dd|
d< Y nw |dpt||dp|jj|	|dpd|
d}tt t t ||t tjd}| j|d | j| t| j| jkr|   I dH  W dS W dS  ty } zt!"dt| dt#$   W Y d}~dS d}~ww )a  
        Log proxy-level failures (e.g. 401 auth, DB connection errors) to Datadog.

        Ensures failures that occur before or outside the LLM completion flow
        (e.g. ConnectError during auth when DB is down) are visible in Datadog
        alongside Prometheus.
        r   )StandardLoggingPayloadSetup
safe_dumps)rW   rY   Z
error_code N)LiteLLMProxyRequestSetup)rX   Zrequest_routeZteam_idZuser_idZend_user_iderror_messageerror_classrN   )r:   r`   status_coderN   rX   ZddsourceZddtagshostnamemessageservicestatus
dd_payloadz(Datadog: async_post_call_failure_hook - rK   )%*litellm.litellm_core_utils.litellm_loggingrZ   *litellm.litellm_core_utils.safe_json_dumpsr\   Zget_error_informationgetr;   stripisdigitintZ$litellm.proxy.litellm_pre_call_utilsr^   Z'get_sanitized_user_information_from_keyrE   dictr9   hasattrgetattrrA   __name__r   r   r   r   r   r   ERROR_add_trace_context_to_payload	log_queueappendlenr'   async_send_batchr	   r:   rN   rO   )r<   rV   rW   rX   rY   rZ   r\   Zerror_information_codera   Zuser_contextr^   _metaZmessage_payloadrh   r?   r(   r(   rB   async_post_call_failure_hook   s   






z*DataDogLogger.async_post_call_failure_hookc              
      s  zi| j std W dS tdt| j | j | jr td | | j I dH }|jdkr8tt	j
j W dS |  |jdkrMtd|j d|j | jr_td	t| j  d
 W dS td|j|j W dS  ty } ztdt| dt   W Y d}~dS d}~ww )z
        Sends the in memory logs queue to datadog api

        Logs sent to /api/v2/logs

        DD Ref: https://docs.datadoghq.com/api/latest/logs/

        Raises:
            Raises a NON Blocking verbose_logger.exception if an error occurs
        z!Datadog: log_queue does not existNz(Datadog - about to flush %s events on %sz@[DATADOG MOCK] Mock mode enabled - API calls will be interceptedi     'Response from datadog API status_code: , text: z[DATADOG MOCK] Batch of z events successfully mocked<Datadog: Response from datadog API status_code: %s, text: %sz"Datadog Error sending batch API - rK   )ru   r	   r:   r)   rw   r2   r*   async_send_compressed_datara   r   ZDATADOG_413_ERRORvalueraise_for_statusr9   textr;   rN   rO   )r<   responser?   r(   r(   rB   rx   7  sL   




zDataDogLogger.async_send_batchc           	   
   C   s   zMt jdu r| j||||d}n	| j||||d}i }| jr#| j|d< | jj| j||d}|  |j	dkrBt
d|j	 d|j td|j	|j W dS  t
yo } ztd	t| d
t   W Y d}~dS d}~ww )z
        Sync Log success events to Datadog

        - Creates a Datadog payload
        - instantly logs it on DD API
        Tr=   rQ   rR   rS   
DD-API-KEY)urljsonheadersr|   r}   r~   r   rJ   rK   N)rD   Zdatadog_use_v1_create_v0_logging_payloadcreate_datadog_logging_payloadrH   r3   postr2   r   ra   r9   r   r	   r)   r:   r;   rN   rO   )	r<   r=   rQ   rR   rS   rh   r   r   r?   r(   r(   rB   log_success_eventl  sR   



zDataDogLogger.log_success_eventc                    sZ   | j ||||d}| j| td| j d t| j| jkr+|  I d H  d S d S )Nr   z-Datadog, event added to queue. Will flush in z seconds...)	r   ru   rv   r	   r)   Zflush_intervalrw   r'   rx   )r<   r=   rQ   rR   rS   rh   r(   r(   rB   rM     s   zDataDogLogger._log_async_eventstandard_logging_objectrf   c                 C   sP   ddl m} ||}td| tt t|dt |t |d}| j	|d |S )Nr   r[   &Datadog: Logger - Logging payload = %s)r   rb   rg   )
rj   r\   r	   r)   r   r   r   r   r   rt   )r<   r   rf   r\   json_payloadrh   r(   r(   rB   &_create_datadog_logging_payload_helper  s   z4DataDogLogger._create_datadog_logging_payload_helperr=   rQ   rR   rS   c                 C   sR   | dd}|du rtdtj}| ddkrtj}| | | j||d}|S )a  
        Helper function to create a datadog payload for logging

        Args:
            kwargs (Union[dict, Any]): request kwargs
            response_obj (Any): llm api response
            start_time (datetime.datetime): start time of request
            end_time (datetime.datetime): end time of request

        Returns:
            DatadogPayload: defined in types.py
        r   Nz+standard_logging_object not found in kwargsrf   Zfailurer   rf   )rk   
ValueErrorr   INFOrs   Z)truncate_standard_logging_payload_contentr   )r<   r=   rQ   rR   rS   r   rf   rh   r(   r(   rB   r     s   
z,DataDogLogger.create_datadog_logging_payloaddatac                    sb   ddl }ddlm} |||d}ddd}| jr"| j|d< | jj| j||d	I dH }|S )
a;  
        Async helper to send compressed data to datadog self.intake_url

        Datadog recommends using gzip to compress data
        https://docs.datadoghq.com/api/latest/logs/

        "Datadog recommends sending your logs compressed. Add the Content-Encoding: gzip header to the request when sending"
        r   Nr[   zutf-8gzipzapplication/json)zContent-EncodingzContent-Typer   )r   r   r   )	r   rj   r\   compressencoderH   r-   r   r2   )r<   r   r   r\   Zcompressed_datar   r   r(   r(   rB   r     s   

z(DataDogLogger.async_send_compressed_datar]   payloaderrorparent_otel_spanevent_metadatac              
      s   z-|  }||pi  ddlm} ||}	tt t t |	t t	j
d}
| j|
 W dS  tyI } ztd|  W Y d}~dS d}~ww )z
        Logs failures from Redis, Postgres (Adjacent systems), as 'WARNING' on DataDog

        - example - Redis is failing / erroring, will be logged on DataDog
        r   r[   rb   ;Datadog: Logger - Exception in async_service_failure_hook: N)rF   r,   rj   r\   r   r   r   r   r   r   WARNru   rv   r9   r	   r:   r<   r   r   r   rR   rS   r   Z_payload_dictr\   Z_dd_message_strZ_dd_payloadr?   r(   r(   rB   async_service_failure_hook  s.   	z(DataDogLogger.async_service_failure_hookc              
      s   z5|j tvr
W dS | }||pi  ddlm} ||}	tt t t	 |	t
 tjd}
| j|
 W dS  tyQ } ztd|  W Y d}~dS d}~ww )z
        Logs success from Redis, Postgres (Adjacent systems), as 'INFO' on DataDog

        No user has asked for this so far, this might be spammy on datatdog. If need arises we can implement this
        Nr   r[   rb   r   )re   DD_LOGGED_SUCCESS_SERVICE_TYPESrF   r,   rj   r\   r   r   r   r   r   r   r   ru   rv   r9   r	   r:   r   r(   r(   rB   async_service_success_hook3  s.   
	z(DataDogLogger.async_service_success_hookc                 C   sl  | di }| di pi }| d}| di }| dd}	| dd}
|d	 }| d
tt }t|}z
||  d }W n tyL   d}Y nw zt|}W n ty^   |}Y nw i }t|trx| D ]\}}|dv rsqj|||< qj||	|
|||| dd| dd|| dd||||d}ddl	m
} ||}td| tt t t |t tjd}|S )z
        Note: This is our V1 Version of DataDog Logging Payload


        (Not Recommended) If you want this to get logged set `litellm.datadog_use_v1 = True`
        litellm_paramsmetadatamessagesoptional_params	call_typezlitellm.completion	cache_hitFusageidi  N)ZendpointZcaching_groupsZprevious_modelsmodelr]   userZresponse_costr   )r   r   r   rR   rS   response_timer   r   Zmodel_parametersZspendr   r   r   r   r[   r   rb   )rk   r;   r
   uuid4ro   total_secondsr9   rE   itemsrj   r\   r	   r)   r   r   r   r   r   r   r   )r<   r=   rQ   rR   rS   r   r   r   r   r   r   r   r   r   Zclean_metadatakeyr   r   r\   r   rh   r(   r(   rB   r   \  sj   





z(DataDogLogger._create_v0_logging_payloadrh   c                 C   sh   z$|   }|du rW dS |d |d< |d}|dur"||d< W dS W dS  ty3   td Y dS w )z2Attach Datadog APM trace context if one is active.Ntrace_idzdd.trace_idspan_idz
dd.span_idz2Datadog: Failed to attach trace context to payload)_get_active_trace_contextrk   r9   r	   r:   )r<   rh   trace_contextr   r(   r(   rB   rt     s   

z+DataDogLogger._add_trace_context_to_payloadc                 C   s   zMd }t tdd }t|r| }|d u r!t tdd }t|r!| }|d u r(W d S t |dd }|d u r5W d S t |dd }dt|i}|d urKt||d< |W S  ty\   td Y d S w )Ncurrent_spanZcurrent_root_spanr   r   z<Datadog: Failed to retrieve active trace context from tracer)rq   r   callabler;   r9   r	   r:   )r<   r   Zcurrent_span_fnZcurrent_root_span_fnr   r   r   r(   r(   rB   r     s2   z'DataDogLogger._get_active_trace_contextc              
      s   ddl m} | }| j|tjd}|g}| |I dH }z|  tdddW S  tj	yC } ztd|j
jdW  Y d}~S d}~w ty\ } ztdt|dW  Y d}~S d}~ww )z1
        Check if the service is healthy
        r   )%create_dummy_standard_logging_payloadr   NZhealthy)rf   r_   Z	unhealthy)ri   r   r   r   r   r   r   r   httpxZHTTPStatusErrorr   r   r9   r;   )r<   r   r   rh   ru   r   r?   r(   r(   rB   async_health_check  s8   z DataDogLogger.async_health_check
request_idstart_time_utcend_time_utcc                    s   d S Nr(   )r<   r   r   r   r(   r(   rB   get_request_response_payload  s   z*DataDogLogger.get_request_response_payload)rC   Nr   )r]   NNNN))rr   
__module____qualname__r8   r   r+   r;   r0   r1   rT   rU   ro   r9   r   r   r{   rx   r   rM   r    r   r   r   r   r   r   r   r   r   r   datetimeObjfloatr   r   r   rt   r   r   r   r   __classcell__r(   r(   r@   rB   r#   F   s    ?

Z56


'$
(
)

U
 r#   )7__doc__r4   r   r.   rN   r   typingr   r   r   r   r   r   r   rD   Zlitellm._loggingr	   Zlitellm._uuidr
   Z(litellm.integrations.custom_batch_loggerr   Z0litellm.integrations.datadog.datadog_mock_clientr   r   Z,litellm.integrations.datadog.datadog_handlerr   r   r   r   r   Z%litellm.litellm_core_utils.dd_tracingr   Z&litellm.llms.custom_httpx.http_handlerr   r   r   Z,litellm.types.integrations.base_health_checkr   Z"litellm.types.integrations.datadogr   r   r   r   r   r   Zlitellm.types.servicesr   r   Zlitellm.types.utilsr    Zadditional_logging_utilsr"   ZRESET_BUDGET_JOBr   r#   r(   r(   r(   rB   <module>   s8     
