o
    ưiH                     @   s   d Z ddlZddlZddlZddlmZ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 ddlmZmZ dd	lmZmZmZ dd
lmZmZ ddlmZmZ G dd deZdS )ao  
PostHog Integration - sends LLM analytics events to PostHog

Follows PostHog's LLM Analytics format: https://posthog.com/docs/llm-analytics/manual-capture

async_log_success_event: stores batch of events in memory and flushes to PostHog
async_log_failure_event: logs failed LLM calls with error information

For batching specific details see CustomBatchLogger class
    N)AnyDictOptionalTuple)verbose_logger)uuid)CustomBatchLogger)
safe_dumps)should_use_posthog_mockcreate_mock_posthog_client)_get_httpx_clientget_async_httpx_clienthttpxSpecialProvider)POSTHOG_MAX_BATCH_SIZEPostHogEventPayload)StandardCallbackDynamicParamsStandardLoggingPayloadc                
       s  e Zd Z fddZdd Zdd Zdd Zd1ddZdee	e
f defddZdedee	e
f de	dee	e
f fddZdee	e
f dee	e
f fddZdee	e
f dee	e
f fddZdedee	e
f de	fddZdee	e
f deee	 ee	 f fddZdd Zd d! Zdee	e
f dee	e
f fd"d#Zde	fd$d%Zd&ed'e	dee	e
f fd(d)Zd2d*e
d+e	d,e
de
fd-d.Zd/d0 Z  ZS )3PostHogLoggerc              
      s   zdt d t | _| jrt  t d tdddu r!tdtt	j
d| _t | _td| _tdd}|d	| _| j d
| _d| _d| _g | _t| j t jdi |dtd W dS  ty| } zt dt|  |d}~ww )a  
        Initializes the PostHog logger, checks if the correct env variables are set

        Required environment variables:
        `POSTHOG_API_KEY` - your PostHog API key
        `POSTHOG_API_URL` - your PostHog API URL (defaults to https://app.posthog.com)
        zPostHog: in init posthog loggerz6[POSTHOG MOCK] PostHog logger initialized in mock modePOSTHOG_API_KEYNz4POSTHOG_API_KEY is not set, set 'POSTHOG_API_KEY=<>')Zllm_providerZPOSTHOG_API_URLzhttps://us.i.posthog.com//batch/F)
flush_lock
batch_sizez.PostHog: Got exception on init PostHog client  )r   debugr
   is_mock_moder   osgetenv	Exceptionr   r   ZLoggingCallbackasync_clientr   sync_clientr   rstripposthog_hostcapture_url_async_initializedr   	log_queueatexitregister_flush_on_exitsuper__init__r   	exceptionstr)selfkwargsposthog_api_urle	__class__r   S/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/posthog.pyr*   &   s@   


zPostHogLogger.__init__c              
   C   s  zdt d| | |\}}|d u s|d u rtd| |}ddi}| |g|}	|d d}
| jj|
t	|	|d}|
  |jdkrRtd	|j d
|j | jr]t d W d S t d W d S  ty } zt dt|  W Y d }~d S d }~ww )Nz<PostHog: Sync logging - Enters logging function for model %sz'PostHog credentials not found in kwargsContent-Typeapplication/jsonr   r   urlcontentheaders   'Response from PostHog API status_code: , text: z-[POSTHOG MOCK] Sync event successfully mockedz%PostHog: Sync event successfully sentzPostHog Sync Layer Error - )r   r   _get_credentials_for_requestr   create_posthog_event_payload_create_posthog_payloadr!   r    postr	   raise_for_statusstatus_codetextr   r+   r,   )r-   r.   response_obj
start_timeend_timeapi_keyapi_urlevent_payloadr9   payloadr#   responser0   r   r   r3   log_success_eventT   s:   

"zPostHogLogger.log_success_eventc              
      n   zt d| |   | ||||I d H  W d S  ty6 } zt dt|  W Y d }~d S d }~ww Nz=PostHog: Async logging - Enters logging function for model %szPostHog Layer Error - r   r   _ensure_async_setup_log_async_eventr   r+   r,   r-   r.   rD   rE   rF   r0   r   r   r3   async_log_success_eventz      z%PostHogLogger.async_log_success_eventc              
      rM   rN   rO   rR   r   r   r3   async_log_failure_event   rT   z%PostHogLogger.async_log_failure_eventN        c                    sh   |  |\}}| |}| j|||d td| j d t| j| jkr2| 	 I d H  d S d S )N)eventrG   rH   z-PostHog, event added to queue. Will flush in z seconds...)
r=   r>   r%   appendr   r   Zflush_intervallenr   Zflush_queue)r-   r.   rD   rE   rF   rG   rH   rI   r   r   r3   rQ      s   
zPostHogLogger._log_async_eventr.   returnc                 C   sb   | dd}|du rtd| dd}|dkrdnd}| j|||d	}| ||}t|||d
S )z
        Helper function to create a PostHog event payload for logging

        Args:
            kwargs (Dict[str, Any]): request kwargs containing standard_logging_object

        Returns:
            PostHogEventPayload: defined in types.py
        standard_logging_objectNz+standard_logging_object not found in kwargs	call_type Z	embeddingz$ai_embedding$ai_generation)r[   r.   
event_name)rW   
propertiesdistinct_id)get
ValueError_create_posthog_properties_get_distinct_idr   )r-   r.   r[   r\   r_   r`   ra   r   r   r3   r>      s$   
z*PostHogLogger.create_posthog_event_payloadr[   r_   c           	      C   s  i }|  |dd|d< |  |dd|d< |  |d}|dur"||d< |d	kr4|  |d
}|dur4||d< |  |dd|d< |d	krJ|  |dd|d< |  |d}|durX||d< |  |dd|d< |  |ddkr{d|d< |  |d}|dur{||d< | || | || |S )z6Create PostHog properties following LLM Analytics specmodelr]   z	$ai_modelZcustom_llm_providerz$ai_providermessagesNz	$ai_inputr^   rK   z$ai_output_choicesZprompt_tokensr   z$ai_input_tokensZcompletion_tokensz$ai_output_tokensresponse_costz$ai_total_cost_usdZresponse_timerV   z$ai_latencystatusZfailureTz$ai_is_error	error_strz	$ai_error)	_safe_get_add_trace_properties_add_custom_metadata_properties)	r-   r[   r.   r_   r`   rg   rK   rh   rj   r   r   r3   rd      s2   z(PostHogLogger._create_posthog_propertiesr`   c                 C   st   |  |di }|  |d|  }||d< |  |d|  }||d< | |}|dp/|d}|r8||d< d S d S )	Nr[   trace_idz$ai_trace_ididz$ai_span_idparent_run_id	parent_idz$ai_parent_id)rk   
_safe_uuid_extract_metadatarb   )r-   r`   r.   r[   rn   Zspan_idmetadatarq   r   r   r3   rl      s   
z#PostHogLogger._add_trace_propertiesc                 C   sF   |  |}t|tsdS h d}| D ]\}}||vr |||< qdS )z0Add custom metadata fields to PostHog propertiesN>    Zhidden_paramsZlitellm_parent_otel_spanuser_idZuser_api_key_user_emailZmodel_groupZuser_api_keyZrequester_ip_addressZendpointZ
model_inforq   Zmodel_group_sizeZuser_api_key_hashZuser_api_end_user_max_budgetZuser_api_key_org_idZuser_api_key_aliasZuser_api_key_model_max_budgetZuser_api_key_metadataZ
deploymentr9   Zlitellm_api_versionrp   Zglobal_max_parallel_requestsZuser_api_key_user_idZuser_api_key_team_aliasZuser_api_key_team_spendZuser_api_key_spendZuser_api_key_end_user_idZuser_api_key_team_max_budgetZuser_api_key_max_budgetZapi_baseZuser_api_key_team_idZcaching_groups)rs   
isinstancedictitems)r-   r`   r.   rt   Zlitellm_internal_fieldskeyvaluer   r   r3   rm     s   

z-PostHogLogger._add_custom_metadata_propertiesc                 C   sZ   |  |}| |d}|rt|S | |d}|rt|S | |d}|r)t|S |  S )Nru   end_userrn   )rs   rk   r,   rr   )r-   r[   r.   rt   ru   r{   rn   r   r   r3   re     s   
zPostHogLogger._get_distinct_idc                 C   sP   | dd}|dur| dp| j}| dp| j}||fS | j}| j}||fS )ap  
        Get PostHog credentials for this request.

        Checks for per-request credentials in standard_callback_dynamic_params,
        falls back to instance defaults from environment variables.

        Args:
            kwargs: Request kwargs containing standard_callback_dynamic_params

        Returns:
            tuple[str, str]: (api_key, api_url)
         standard_callback_dynamic_paramsNZposthog_api_keyr/   )rb   r   r"   )r-   r.   r|   rG   rH   r   r   r3   r=   )  s   
z*PostHogLogger._get_credentials_for_requestc              
      sv  z| j sW dS tdt| j  d | jrtd i }| j D ]}|d |d f}||vr3g ||< || |d  q!| D ];\\}}}dd	i}| ||}|d
 d}	| j	j
|	t||dI dH }
|
  |
jdkr|td|
j d|
j qA| jrtdt| j  d W dS tdt| j  d W dS  ty } ztdt|  W Y d}~dS d}~ww )z
        Sends the in memory logs queue to PostHog API

        Raises:
            Raises a NON Blocking verbose_logger.exception if an error occurs
        NzPostHog: Sending batch of z eventsz@[POSTHOG MOCK] Mock mode enabled - API calls will be interceptedrG   rH   rW   r4   r5   r   r   r6   r:   r;   r<   z[POSTHOG MOCK] Batch of z events successfully mockedzPostHog: Batch of z events successfully sentz"PostHog Error sending batch API - )r%   r   r   rY   r   rX   rx   r?   r!   r   r@   r	   rA   rB   r   rC   r+   r,   r-   Zbatches_by_credentialsitemry   rG   rH   eventsr9   rJ   r#   rK   r0   r   r   r3   async_send_batchC  sP   



"zPostHogLogger.async_send_batchc              
   C   sh   | j s2zt | _t|   d| _ td W d S  ty1 } zt	dt
|   d }~ww d S )NTz%PostHog: Async components initializedz0PostHog: Failed to initialize async components: )r$   asyncioLockr   create_taskZperiodic_flushr   r   r   errorr,   )r-   r0   r   r   r3   rP   {  s   
z!PostHogLogger._ensure_async_setupc                 C   s    | di pi }| di pi S )Nlitellm_paramsrt   )rb   )r-   r.   r   r   r   r3   rs     s   zPostHogLogger._extract_metadatac                 C   s   t t S N)r,   r   uuid4)r-   r   r   r3   rr     s   zPostHogLogger._safe_uuidr   rG   c                 C   s
   ||dS )N)rG   batchr   )r-   r   rG   r   r   r3   r?     s   
z%PostHogLogger._create_posthog_payloadobjry   defaultc                 C   s"   |d u s	t |ds|S |||S )Nrb   )hasattrrb   )r-   r   ry   r   r   r   r3   rk     s   zPostHogLogger._safe_getc              
   C   s\  | j sdS tdt| j  d zi }| j D ]}|d |d f}||vr)g ||< || |d  q| D ]5\\}}}ddi}| ||}|d	 d
}	| jj	|	t
||d}
|
  |
jdkrltd|
j  q7| jr}tdt| j  d ntdt| j  d | j   W dS  ty } ztdt|  W Y d}~dS d}~ww )a  
        Flush remaining events from internal log_queue before process exit.
        Called automatically via atexit handler.

        This works in conjunction with GLOBAL_LOGGING_WORKER's atexit handler:
        1. GLOBAL_LOGGING_WORKER atexit invokes pending callbacks
        2. Callbacks add events to this logger's internal log_queue
        3. This atexit handler flushes the internal queue to PostHog
        NzPostHog: Flushing z remaining events on exitrG   rH   rW   r4   r5   r   r   r6   r:   z*PostHog: Failed to flush on exit - status z$[POSTHOG MOCK] Successfully flushed z events on exitzPostHog: Successfully flushed z(PostHog: Error flushing events on exit: )r%   r   r   rY   rX   rx   r?   r!   r    r@   r	   rA   rB   r   r   clearr   r,   r}   r   r   r3   r(     sP   



"zPostHogLogger._flush_on_exit)NrV   rV   r   )__name__
__module____qualname__r*   rL   rS   rU   rQ   r   r,   r   r   r>   r   rd   rl   rm   re   r   r   r=   r   rP   rs   rr   listr?   rk   r(   __classcell__r   r   r1   r3   r   %   sB    .&
!


"2"

*8"r   )__doc__r   r&   r   typingr   r   r   r   Zlitellm._loggingr   Zlitellm._uuidr   Z(litellm.integrations.custom_batch_loggerr   Z*litellm.litellm_core_utils.safe_json_dumpsr	   Z(litellm.integrations.posthog_mock_clientr
   r   Z&litellm.llms.custom_httpx.http_handlerr   r   r   Z"litellm.types.integrations.posthogr   r   Zlitellm.types.utilsr   r   r   r   r   r   r3   <module>   s    