
    AHj+A                         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rd dlmZ neZ G d d	e      Zy)
    N)datetime)TYPE_CHECKINGAnyListOptionalcast)verbose_logger!CLOUDZERO_EXPORT_INTERVAL_MINUTESCustomLogger)AsyncIOSchedulerc            
            e Zd ZdZ	 	 	 ddee   dee   dee   f fdZd Zd Z	 	 	 	 ddee	   d	ed
ee
   dee
   fdZddee	   fdZd Zedefd       Z x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)
    api_keyconnection_idtimezonec                 8   t        |   di | |xs t        j                  d      | _        |xs t        j                  d      | _        |xs t        j                  dd      | _        t        j                  d| j
                   d| j                          y)	zXInitialize CloudZero logger with configuration from parameters or environment variables.CLOUDZERO_API_KEYCLOUDZERO_CONNECTION_IDCLOUDZERO_TIMEZONEUTCz1CloudZero Logger initialized with connection ID: z, timezone: N )	super__init__osgetenvr   r   r   r	   debug)selfr   r   r   kwargs	__class__s        `/root/tools/cai/cai_env/lib/python3.12/site-packages/litellm/integrations/cloudzero/cloudzero.pyr   zCloudZeroLogger.__init__   s     	"6" @")),?"@*Rbii8Q.R JBII.BE$J?@R@R?SS_`d`m`m_no	
    c                   K   ddl m} ddlm} |j                  j
                  }|r[|j                  rO|j                  |       d{   r4	 | j                          d{    |j                  |       d{    yy| j                          d{    y7 R7 ;7 ## |j                  |       d{  7   w xY w7 +w)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)
cronjob_idN)
litellm.constantsr%   litellm.proxy.proxy_serverr&   db_spend_update_writerpod_lock_managerredis_cacheacquire_lock_hourly_usage_data_exportrelease_lock)r   r%   r&   r+   s       r"   initialize_cloudzero_export_jobz/CloudZeroLogger.initialize_cloudzero_export_job,   s     	
 	A,CCTT  0 < <%22? 3   88:::*77#G 8    00222 ;*77#G 8   
 3sf   ACB	CB! !B"B! &C;B<CCCB! C!B>7B:8B>>Cc                    K   ddl m}m} ddlm} t        j
                  |j                        }| |t        dz        z
  }| j                  |d||       d{    y7 w)	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   r2   r   r(   r3   nowutcr   export_usage_data)r   r2   r   r3   current_time_utcone_hour_ago_utcs         r"   r.   z)CloudZeroLogger._hourly_usage_data_exportL   sf      	1H#<<5+i59/
 
 $$4&+)	 % 
 	
 	
s   AA#A!A#r8   r9   r:   r;   c                   K   ddl m} ddlm} ddlm} 	 t        j                  d       | j                  r| j                  st        d       |       }t        j                  d       |j                  |||       d	{   }	|	j                         rt        j                  d
       y	t        j                  dt        |	       d        |       }
|
j                  |	      }|j                         rt        j                  d       y	 || j                  | j                  | j                         }t        j                  dt        |       d       |j#                  ||       t        j                  dt        |       d       y	7 # t$        $ r'}t        j&                  dt)        |               d	}~ww xY 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)r8   r:   r;   Nz/CloudZero Logger: No usage data found to exportzCloudZero Logger: Processing  recordsz4CloudZero Logger: No valid data after transformation)r   r   user_timezonezCloudZero Logger: Transmitting z records to CloudZero)r9   z(CloudZero Logger: Successfully exported z.CloudZero Logger: Error exporting usage data: ),litellm.integrations.cloudzero.cz_stream_apirB   'litellm.integrations.cloudzero.databaserD   (litellm.integrations.cloudzero.transformrF   r	   r   r   r   
ValueErrorget_usage_datais_emptylen	transformwarningr   send_batched	Exceptionerrorstr)r   r8   r9   r:   r;   rB   rD   rF   databasedatatransformercbf_datastreameres                 r"   r>   z!CloudZeroLogger.export_usage_datac   s    $ 	SKK4	  !OP <<t'9'9  G 
 '(H  !UV!00N 1  D }}$$%VW  #@T8!TU )*K",,T2H  "&&J  )"00"mmH   1#h-@UV !!(i!@  :3x=/I^_AH  	  @QI 		sU   GA+F F)F +G,AF GB F GF 	G "F;;G  Gc                 r  K   ddl m} ddlm} 	 t	        j
                  d        |       }t	        j
                  d       |j                  |       d{   }|j                         r!t	        j                  d       g g dddddd	d
S t	        j
                  dt        |       d       |j                  d      j                         } |       }|j                  |      }|j                         rJt	        j                  d       |g t        |      t        d |D              t        d |D              ddd	d
S |j                         }	t        d |	D              }
t        t        d |	D                    }t        t        d |	D                    }t        d |	D              }t	        j
                  dt        |       d       ||	t        |	      |
|||d	d
S 7 # t        $ rH}t	        j                   dt#        |              t	        j                   dt#        |               d}~ww xY 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   rC   rE   z)CloudZero Logger: Starting dry run exportz0CloudZero Logger: Loading usage data for dry run)r8   Nz&CloudZero Dry Run: No usage data found)total_records
total_costtotal_tokensunique_accountsunique_services)
usage_datarY   summaryzCloudZero Dry Run: Processing z records...2   z5CloudZero Dry Run: No valid data after transformationc              3   @   K   | ]  }|j                  d d        yw)spendr   Nget.0rows     r"   	<genexpr>z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>   s       *47CGGGQ/*   c              3   f   K   | ])  }|j                  d d      |j                  dd      z    + yw)prompt_tokensr   completion_tokensNrg   ri   s     r"   rl   z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>   s9      , !$  GGOQ7!gg&91=>,s   /1c              3   @   K   | ]  }|j                  d d        yw	cost/costr   Nrg   rj   records     r"   rl   z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>   s     TFVZZQ7Trm   c              3   b   K   | ]'  }|j                  d       r|j                  d d       ) ywresource/account Nrg   rt   s     r"   rl   z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>   1      zz"45 JJ126   -/c              3   b   K   | ]'  }|j                  d       r|j                  d d       ) ywresource/servicery   Nrg   rt   s     r"   rl   z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>   rz   r{   c              3   @   K   | ]  }|j                  d d        ywusage/amountr   Nrg   rt   s     r"   rl   z<CloudZeroLogger.dry_run_export_usage_data.<locals>.<genexpr>  s       28

>1-rm   z(CloudZero Logger: Dry run completed for rG   z+CloudZero Logger: Error in dry run export: zCloudZero Dry Run Error: )rJ   rD   rK   rF   r	   r   rM   rN   rQ   rO   headto_dictsrP   sumsetrS   rT   rU   )r   r8   rD   rF   rV   rW   usage_data_samplerX   rY   cbf_data_dictr^   r`   ra   r_   r[   s                  r"   dry_run_export_usage_dataz)CloudZeroLogger.dry_run_export_usage_data   sk     	LKa	  !LM '(H  !ST!00u0==D}}&&'OP"$ ")*&'()+,+, 
 
   0T;G
 !%		" 6 6 8 )*K",,T2H  "&&K #4 "),->)?&) *;L* ' ), , (9, )
 ,-+,  & %--/M TmTTJ! "/ O " "/ O  <I L   :3x=/R
 0)%(%7",$0'6'6
 
Y >p  	  #NsSTvh!WX  #<SVH!EF	sV   H7AG# G 4G# H7B2G# >H7?B G# H7 G# #	H4,AH//H44H7c                    ddl m} ddlm} ddlm}  |       }|j                         r|j                  d       y|j                  dt        |       d       |j                         } |d	d
|d      }|j                  ddd       |j                  dddd       |j                  dddd       |j                  dddd       |j                  ddd       |j                  ddd       |j                  ddd       |j                  ddd       |j                  dddd       |j                  ddd       |j                  d dd       |j                  d!d"d       |j                  d#d$d       |D ]  }t        |j                  dd%            }	t        |j                  dd            }
t        |j                  dd            }t        |j                  dd%            }t        |j                  d d%            }t        |j                  d!d%            }t        |j                  d#d%            }t        |j                  dd%            }t        |j                  dd%            }t        |j                  d&d%            }t        |j                  d'd%            }t        |j                  d(d%            }t        |j                  d)d%            }|j                  |	|
|||||||||||        |j                  |       t        d* |D              }t        t        d+ |D                    }t        t        d, |D                    }t        d- |D              }|j                  d.       |j                  d/t        |      d0       |j                  d1|d2       |j                  d3|d0       |j                  d4|        |j                  d5|        |j                  d6       y)7z<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_wraprs   greenright)r   justifyr   entity_typemagenta	entity_idteam_idcyan
team_alias
user_emailapi_key_aliasyellowr   zresource/idr~   rx   whitezresource/regiondimzN/Azresource/tag:team_idzresource/tag:team_aliaszresource/tag:user_emailzresource/tag:api_key_aliasc              3   @   K   | ]  }|j                  d d        ywrr   rg   rt   s     r"   rl   z>CloudZeroLogger._display_cbf_data_on_screen.<locals>.<genexpr>m  s     JK3Jrm   c              3   b   K   | ]'  }|j                  d       r|j                  d d       ) ywrw   rg   rt   s     r"   rl   z>CloudZeroLogger._display_cbf_data_on_screen.<locals>.<genexpr>o  1      ::01 

-r2r{   c              3   b   K   | ]'  }|j                  d       r|j                  d d       ) ywr}   rg   rt   s     r"   rl   z>CloudZeroLogger._display_cbf_data_on_screen.<locals>.<genexpr>v  r   r{   c              3   @   K   | ]  }|j                  d d        ywr   rg   rt   s     r"   rl   z>CloudZeroLogger._display_cbf_data_on_screen.<locals>.<genexpr>~  s     OV6::na8Orm   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])rich.boxr   rich.consoler   
rich.tabler   rN   printrO   r   
add_columnrU   rh   add_rowr   r   )r   rY   r   r   r   consolerecords	cbf_tableru   time_usage_start	cost_costusage_amountresource_idresource_serviceresource_accountresource_regionr   r   r   r   r   r   r^   r`   ra   r_   s                             r"   _display_cbf_data_on_screenz+CloudZeroLogger._display_cbf_data_on_screen  s   #($)MMCDA#h-Pfg	

 ##% ;FF
	 	/vuM[RWXGU 	 	
 	y'5 	 	
 	YfeD\G\G_HeL(GU 	 	
 	])UK/vuM/wN.eUK 	F"6::.@%#HIFJJ{A67Ivzz.!<=Lfjj>?K"6::.@%#HI"6::.@%#HI!&**->"FGOfjj>?KFJJ{E:;I&**%;UCDGVZZ(A5IJJVZZ(A5IJJ

+G OPM   !	@ 	i  J'JJ
 % 
  % 
 OwOOABCL#345
3'789(a(89:+O+<=>+O+<=>\	
r#   	schedulerc                 Z  K   ddl m} ddlm} t        j
                  j                  t              }t        j                  dt        |             t        |      dkD  rJt        t        |d         }t        j                  d|z         | j                  |j                  d|       y	y	w)
z
        Initialize the CloudZero background job.

        Starts the background job that exports the usage data to CloudZero every hour.
        r   r
   r   )callback_typezfound %s cloudzero loggerszNInitializing remaining budget metrics as a cron job executing every %s minutesintervalr5   N)r(   r   "litellm.integrations.custom_loggerr   litellmlogging_callback_managerget_custom_loggers_for_typer   r	   r   rO   r   add_jobr0   )r   r   r   prometheus_loggerscloudzero_loggers        r"   init_cloudzero_background_jobz-CloudZeroLogger.init_cloudzero_background_job  s      	HC ,,HH) I 
 	 	93?Q;RS!"Q&#O5G5JK  `34  @@9   's   B)B+)NNN)Nr7   NN)i'  )__name__
__module____qualname____doc__r   rU   r   r0   r.   intr   r>   r   r   staticmethodr   r   __classcell__)r!   s   @r"   r   r      s     "&'+"&	
#
  }
 3-	
$3@
2  $)-1+/J}J J !*	J
 x(JXnXc] n`j
X 7G  r#   r   )r   r   typingr   r   r   r   r   r   litellm._loggingr	   r(   r   r   r   apscheduler.schedulers.asyncior   r   r   r#   r"   <module>r      s7    	  ; ;  + ? ;?Vl Vr#   