o
    ưi+A                     @   s   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mZ d dlmZ er7d dlmZ neZG dd	 d	eZdS )
    N)datetime)TYPE_CHECKINGAnyListOptionalcast)verbose_logger!CLOUDZERO_EXPORT_INTERVAL_MINUTESCustomLogger)AsyncIOSchedulerc                
       s   e Zd ZdZ			ddee dee dee f fddZdd	 Zd
d Z				ddee	 dedee
 dee
 fddZddee	 fddZdd ZedefddZ  ZS )CloudZeroLoggeraD  
    CloudZero Logger for exporting LiteLLM usage data to CloudZero AnyCost API.

    Environment Variables:
        CLOUDZERO_API_KEY: CloudZero API key for authentication
        CLOUDZERO_CONNECTION_ID: CloudZero connection ID for data submission
        CLOUDZERO_TIMEZONE: Timezone for date handling (default: UTC)
    Napi_keyconnection_idtimezonec                    sb   t  jdi | |ptd| _|ptd| _|p tdd| _td| j d| j  dS )	zXInitialize CloudZero logger with configuration from parameters or environment variables.ZCLOUDZERO_API_KEYZCLOUDZERO_CONNECTION_IDZCLOUDZERO_TIMEZONEUTCz1CloudZero Logger initialized with connection ID: z, timezone: N )	super__init__osgetenvr   r   r   r   debug)selfr   r   r   kwargs	__class__r   _/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/cloudzero/cloudzero.pyr      s   zCloudZeroLogger.__init__c              	      s   ddl m} ddlm} |jj}|r?|jr?|j|dI dH r=z|  I dH  W |j	|dI dH  dS |j	|dI dH  w dS |  I dH  dS )aa  
        Handler for initializing CloudZero export job.

        Runs when CloudZero logger starts up.

        - If redis cache is available, we use the pod lock manager to acquire a lock and export the data.
            - Ensures only one pod exports the data at a time.
        - If redis cache is not available, we export the data directly.
        r   )$CLOUDZERO_EXPORT_USAGE_DATA_JOB_NAME)proxy_logging_obj)Z
cronjob_idN)
litellm.constantsr   Zlitellm.proxy.proxy_serverr   Zdb_spend_update_writerpod_lock_managerredis_cacheacquire_lock_hourly_usage_data_exportrelease_lock)r   r   r   r!   r   r   r   initialize_cloudzero_export_job,   s"   

z/CloudZeroLogger.initialize_cloudzero_export_jobc                    sX   ddl m}m} ddlm} t |j}||td d }| j|d||dI dH  dS )	z|
        Exports the hourly usage data to CloudZero.

        Start time: 1 hour ago
        End time: current time
        r   )	timedeltar   )"CLOUDZERO_MAX_FETCHED_DATA_RECORDS   minutesreplace_hourly)limit	operationstart_time_utcend_time_utcN)	r   r'   r   r    r(   nowutcr
   export_usage_data)r   r'   r   r(   Zcurrent_time_utcZone_hour_ago_utcr   r   r   r$   L   s   z)CloudZeroLogger._hourly_usage_data_exportr,   r-   r.   r/   r0   c              
      sD  ddl m} ddlm} ddlm} zwtd | jr| j	s#t
d| }td |j|||dI d	H }	|	 rBtd
 W d	S tdt|	 d | }
|
|	}| ratd W d	S || j| j	| jd}tdt| d |j||d tdt| d W d	S  ty } ztdt|   d	}~ww )aP  
        Exports the usage data to CloudZero.

        - Reads data from the DB
        - Transforms the data to the CloudZero format
        - Sends the data to CloudZero

        Args:
            limit: Optional limit on number of records to export
            operation: CloudZero operation type ("replace_hourly" or "sum")
        r   )CloudZeroStreamerLiteLLMDatabaseCBFTransformerz,CloudZero Logger: Starting usage data exportzpCloudZero configuration missing. Please set CLOUDZERO_API_KEY and CLOUDZERO_CONNECTION_ID environment variables.z2CloudZero Logger: Loading usage data from database)r-   r/   r0   Nz/CloudZero Logger: No usage data found to exportzCloudZero Logger: Processing  recordsz4CloudZero Logger: No valid data after transformation)r   r   Zuser_timezonezCloudZero Logger: Transmitting z records to CloudZero)r.   z(CloudZero Logger: Successfully exported z.CloudZero Logger: Error exporting usage data: )Z,litellm.integrations.cloudzero.cz_stream_apir4   'litellm.integrations.cloudzero.databaser6   (litellm.integrations.cloudzero.transformr8   r   r   r   r   
ValueErrorget_usage_datais_emptylen	transformwarningr   Zsend_batched	Exceptionerrorstr)r   r-   r.   r/   r0   r4   r6   r8   databasedatatransformercbf_datastreamerer   r   r   r3   c   sZ   




z!CloudZeroLogger.export_usage_data'  c              
      s  ddl m} ddlm} ztd | }td |j|dI dH }| r:td g g dddddd	d
W S tdt	| d |
d }| }||}| rztd |g t	|tdd |D tdd |D ddd	d
W S | }	tdd |	D }
t	tdd |	D }t	tdd |	D }tdd |	D }tdt	| d ||	t	|	|
|||d	d
W S  ty } ztdt|  tdt|   d}~ww )a  
        Returns the data that would be exported to CloudZero without actually sending it.

        Args:
            limit: Limit number of records to display (default: 10000)

        Returns:
            dict: Contains usage_data, cbf_data, and summary statistics
        r   r5   r7   z)CloudZero Logger: Starting dry run exportz0CloudZero Logger: Loading usage data for dry run)r-   Nz&CloudZero Dry Run: No usage data found)Ztotal_records
total_costtotal_tokensunique_accountsunique_services)Z
usage_datarH   summaryzCloudZero Dry Run: Processing z records...2   z5CloudZero Dry Run: No valid data after transformationc                 s       | ]	}| d dV  qdS )Zspendr   Nget.0rowr   r   r   	<genexpr>       
z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>c                 s   s(    | ]}| d d| dd V  qdS )Zprompt_tokensr   Zcompletion_tokensNrS   rU   r   r   r   rX      s    


c                 s   rR   	cost/costr   NrS   rV   recordr   r   r   rX          c                 s   &    | ]}| d r| d dV  qdS resource/account NrS   r\   r   r   r   rX          

c                 s   r_   resource/servicerb   NrS   r\   r   r   r   rX      rc   c                 s   rR   usage/amountr   NrS   r\   r   r   r   rX     rY   z(CloudZero Logger: Dry run completed for r9   z+CloudZero Logger: Error in dry run export: zCloudZero Dry Run Error: )r:   r6   r;   r8   r   r   r=   r>   rA   r?   headto_dictsr@   sumsetrB   rC   rD   )r   r-   r6   r8   rE   rF   Zusage_data_samplerG   rH   Zcbf_data_dictrL   rN   rO   rM   rJ   r   r   r   dry_run_export_usage_data   s   




z)CloudZeroLogger.dry_run_export_usage_datac                 C   s  ddl m} ddlm} ddlm} | }| r |d dS |dt| d |	 }|d	d
|dd}|j
dddd |j
ddddd |j
ddddd |j
ddddd |j
dddd |j
dddd |j
dddd |j
dddd |j
ddddd |j
dddd |j
d ddd |j
d!d"dd |j
d#d$dd |D ]{}t|dd%}	t|dd}
t|dd}t|dd%}t|d d%}t|d!d%}t|d#d%}t|dd%}t|dd%}t|d&d%}t|d'd%}t|d(d%}t|d)d%}||	|
||||||||||| q|| td*d+ |D }ttd,d+ |D }ttd-d+ |D }td.d+ |D }|d/ |d0t|d1 |d2|d3 |d4|d1 |d5|  |d6|  |d7 dS )8z<Display CBF transformed data in a formatted table on screen.r   )SIMPLE)Console)Tablez'[yellow]No CBF data to display[/yellow]Nu2   
[bold green]💰 CloudZero CBF Transformed Data (z records)[/bold green]Tz	bold cyan)r      )show_headerheader_styleboxpaddingztime/usage_startblueF)styleno_wrapr[   greenright)rv   justifyrw   entity_typemagenta	entity_idteam_idcyan
team_alias
user_emailapi_key_aliasyellowrg   zresource/idre   ra   whitezresource/regiondimzN/Azresource/tag:team_idzresource/tag:team_aliaszresource/tag:user_emailzresource/tag:api_key_aliasc                 s   rR   rZ   rS   r\   r   r   r   rX   m  r^   z>CloudZeroLogger._display_cbf_data_on_screen.<locals>.<genexpr>c                 s   r_   r`   rS   r\   r   r   r   rX   o  rc   c                 s   r_   rd   rS   r\   r   r   r   rX   v  rc   c                 s   rR   rf   rS   r\   r   r   r   rX   ~  r^   u(   
[bold blue]📊 CBF Summary[/bold blue]z  Records: ,z  Total Cost: $z.2fz  Total Tokens: z  Unique Accounts: z  Unique Services: uM   
[dim]💡 This is the CloudZero CBF format ready for AnyCost ingestion[/dim])Zrich.boxrm   Zrich.consolern   Z
rich.tablero   r>   printr?   ri   
add_columnrD   rT   add_rowrj   rk   )r   rH   rm   rn   ro   consolerecordsZ	cbf_tabler]   Ztime_usage_startZ	cost_costZusage_amountZresource_idZresource_serviceZresource_accountZresource_regionr{   r}   r~   r   r   r   rL   rN   rO   rM   r   r   r   _display_cbf_data_on_screen  s   

	
z+CloudZeroLogger._display_cbf_data_on_screen	schedulerc                    sz   ddl m} ddlm} tjjtd}t	dt
| t
|dkr;tt|d }t	d|  | j|jd|d d	S d	S )
z
        Initialize the CloudZero background job.

        Starts the background job that exports the usage data to CloudZero every hour.
        r   r	   r   )Zcallback_typezfound %s cloudzero loggerszNInitializing remaining budget metrics as a cron job executing every %s minutesintervalr*   N)r    r
   "litellm.integrations.custom_loggerr   litellmZlogging_callback_managerZget_custom_loggers_for_typer   r   r   r?   r   Zadd_jobr&   )r   r
   r   Zprometheus_loggersZcloudzero_loggerr   r   r   init_cloudzero_background_job  s*   
z-CloudZeroLogger.init_cloudzero_background_job)NNN)Nr,   NN)rK   )__name__
__module____qualname____doc__r   rD   r   r&   r$   intr   r3   rl   r   staticmethodr   r   __classcell__r   r   r   r   r      s>     
Lplr   )r   r   typingr   r   r   r   r   r   Zlitellm._loggingr   r    r
   r   r   Zapscheduler.schedulers.asyncior   r   r   r   r   r   <module>   s    