Ë
    tPêjÞ2  ã                   ó(  — U d Z ddlZddl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 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 erddlmZ dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZ eed<   dZ!eed<   dZ"eed<   dZ#eed <   d!Z$eed"<   d#Z%eed$<   d%Z&eed&<   d'Z'eed(<   d)Z(eed*<   d+Z)eed,<   e*e+z  Z, ed-d-¬.«       G d/„ d0«      «       Z-d1e*d2e*fd3„Z.d4e-d2e/e*e,f   fd5„Z0d6ed7e*d8e+d9e*dz  d2e/e*e,f   f
d:„Z1d4e-d2efd;„Z2 G d<„ d=«      Z3d2e+fd>„Z4 ed-d-¬.«       G d?„ d@«      «       Z5dAe*d2e6fdB„Z7dCe*dDe*dEe*d2e*fdF„Z8dGe*dHe*dIe*dz  d2e5fdJ„Z9dKedL   dMe*d2e-dz  fdN„Z: G dO„ dP«      Z; e;«       Z<eedQ<   dRe6dKedL   dMe*d2e3dz  fdS„Z=dUdT„Z>y)Va¯  
Push-based OTLP metering for enterprise litellm deployments.

Owns a dedicated OpenTelemetry meter provider and an OTLP/HTTP exporter
authenticated to our global collector with a TLS client certificate. The
collector front end terminates mutual TLS: the client certificate presented
here is validated against our CA at the edge, and the verified subject is
what identifies the deployment. It is intentionally isolated from the global
meter provider so the customer's own OTEL metrics are untouched and ours
never leak into their backend.

The deployment's identity rides on the TLS client certificate, not on the
payload; the secret license key is never sent as an attribute or header.
é    N)Ú	dataclass)ÚTYPE_CHECKINGÚFinalÚOptional)ÚOTLPMetricExporter)ÚCounter)ÚMeterProvider)ÚPeriodicExportingMetricReader)ÚResource)Úverbose_proxy_logger)ÚBillableCategory)ÚEnterpriseLicenseDataÚ LITELLM_BILLING_METRICS_ENDPOINTÚENDPOINT_ENVÚ#LITELLM_BILLING_METRICS_CLIENT_CERTÚCLIENT_CERT_ENVÚ"LITELLM_BILLING_METRICS_CLIENT_KEYÚCLIENT_KEY_ENVÚLITELLM_BILLING_METRICS_CA_CERTÚCA_CERT_ENVÚ*LITELLM_BILLING_METRICS_EXPORT_INTERVAL_MSÚEXPORT_INTERVAL_ENVi`ê  ÚDEFAULT_EXPORT_INTERVAL_MSiˆ  ÚSHUTDOWN_FLUSH_TIMEOUT_MSz/v1/metricsÚ_METRICS_PATHz
-----BEGINÚ_PEM_PREFIXzlitellm-billing-mtls-Ú_PEM_DIR_PREFIXi€  Ú_PEM_FILE_MODEz
client.crtÚ_CLIENT_CERT_FILENAMEz
client.keyÚ_CLIENT_KEY_FILENAMEzca.crtÚ_CA_CERT_FILENAMEz$litellm.enterprise.billable_requestsÚMETRIC_NAMEzlitellm.enterprise.billingÚ
METER_NAMET)ÚfrozenÚslotsc                   ó`   — e Zd ZU eed<   eed<   eed<   edz  ed<   eed<   eed<   edz  ed<   y)	ÚBillingMetricsConfigÚendpointÚclient_cert_pathÚclient_key_pathNÚca_cert_pathÚexport_interval_msÚlitellm_versionÚ
license_id)Ú__name__Ú
__module__Ú__qualname__ÚstrÚ__annotations__Úint© ó    úu/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/enterprise_billing/billing_metrics.pyr'   r'   ;   s3   … àƒMØÓØÓØ˜‘*ÓØÓØÓØ�d‘
Ôr6   r'   r(   Úreturnc                 óf   — | j                  d«      }|j                  t        «      r|S |› t        › �S )zKThe OTLP/HTTP metric exporter wants the full URL including the signal path.ú/)ÚrstripÚendswithr   )r(   Útrimmeds     r7   Ú_metrics_endpointr>   F   s1   € à—_‘_ SÓ)€GØ×&Ñ&¤}Ô5ˆ7ÐV¸g¸YÄ}ÀoÐ;VÐVr6   Úconfigc                 ód   — d| j                   dœ}| j                  rd| j                  ini }i |¥|¥S )Nzlitellm-proxy)zservice.namezlitellm.versionzlitellm.license.id)r-   r.   )r?   ÚbaseÚlicense_attrs      r7   Ú_resource_attributesrC   L   sE   € à'Ø!×1Ñ1ñ.€Dð \b×[lÒ[lÐ/CÀV×EVÑEVÑ.WÐrt€LØ#ˆdÐ#�lÐ#Ð#r6   ÚcategoryÚrouteÚstatus_codeÚmodel_idc                 ó>   — | j                   ||dœ}|rd|ini }i |¥|¥S )N)zlitellm.endpoint.categoryz
http.routezhttp.response.status_codezlitellm.model_id©Úvalue)rD   rE   rF   rG   rA   Ú
model_attrs         r7   Ú_billable_attributesrL   U   s<   € ð &.§^¡^ØØ%0ñ.€Dñ
 V^Ð4FÈÑ3QÐce€JØ!ˆdÐ!�jÐ!Ð!r6   c                 ó  — t        t        | j                  «      | j                  | j                  | j
                  ¬«      }t        || j                  ¬«      }t        |gt        j                  t        | «      «      ¬«      S )aY  OTLP/HTTP exporter presenting a TLS client certificate.

    The collector's load balancer terminates mutual TLS and validates the client
    certificate against our CA. Server verification uses the system trust store
    (the collector presents a public web-PKI certificate); ca_cert_path overrides
    it only for private/test collectors.
    )r(   Úcertificate_fileÚclient_certificate_fileÚclient_key_file)Úexport_interval_millis)Úmetric_readersÚresource)r   r>   r(   r+   r)   r*   r
   r,   r	   r   ÚcreaterC   )r?   ÚexporterÚreaders      r7   Úbuild_mtls_meter_providerrW   a   si   € ô )Ü" 6§?¡?Ó3à×,Ñ,Ø &× 7Ñ 7Ø×.Ñ.ô€Hô 2°(ÐSY×SlÑSlÔm€FÜ¨¨¼8¿?¹?ÔK_Ð`fÓKgÓ;hÔiÐir6   c            
       óJ   — e Zd ZdZdeddfd„Zdededed	edz  ddf
d
„Z	dd„Z
y)ÚBillingMetricsRecorderzcIncrements one OTLP counter per billable request. The meter provider is injected (see the factory).Úproviderr8   Nc                 ór   — || _         |j                  t        «      j                  t        dd¬«      | _        y )Nz	{request}z<Count of 2xx HTTP requests to billable LLM/MCP/A2A endpoints)ÚnameÚunitÚdescription)Ú	_providerÚ	get_meterr#   Úcreate_counterr"   Ú_counter)ÚselfrZ   s     r7   Ú__init__zBillingMetricsRecorder.__init__w   s5   € Ø!ˆŒØ!)×!3Ñ!3´JÓ!?×!NÑ!NÜØØVð "Oó "
ˆ�r6   rD   rE   rF   rG   c          	      óT   — | j                   j                  dt        ||||«      «       y )Né   )rb   ÚaddrL   )rc   rD   rE   rF   rG   s        r7   ÚrecordzBillingMetricsRecorder.record   s#   € Ø�‰×Ñ˜!Ô1°(¸EÀ;ÐPXÓYÕZr6   c                 óD   — | j                   j                  t        ¬«       y)z‰Final flush + exporter-thread stop. Without this, up to one export
        interval of billable counts is dropped on every proxy restart.)Útimeout_millisN)r_   Úshutdownr   ©rc   s    r7   rk   zBillingMetricsRecorder.shutdown‚   s   € ð 	�‰×ÑÔ/HÐÕIr6   ©r8   N)r/   r0   r1   Ú__doc__r	   rd   r   r2   r4   rh   rk   r5   r6   r7   rY   rY   t   sU   „ Ùmð
 ð 
°4ó 
ð[Ð"2ð [¸3ð [ÈSð [Ð\_ÐbfÑ\fð [Ðkoó [ôJr6   rY   c                  óÆ   — t        j                  t        «      } | €t        S 	 t	        | «      S # t
        $ r) t        j                  dt        | t        «       t        cY S w xY w)Nz$Invalid %s=%r, falling back to %d ms)ÚosÚgetenvr   r   r4   Ú
ValueErrorr   Úwarning)Úraws    r7   Ú_export_interval_msru   ˆ   sZ   € Ü—‘Ô.Ó/€CØ
€{Ü)Ð)ð*Ü�3‹xˆøÜò *Ü×$Ñ$Ø2Ô4GÈÔNhô	
ô *Ò)ð	*ús   £
. ®/A ÁA c                   ó2   — e Zd ZU eed<   eed<   edz  ed<   y)Ú_CredentialPathsr)   r*   Nr+   )r/   r0   r1   r2   r3   r5   r6   r7   rw   rw   •   s   … àÓØÓØ˜‘*Ôr6   rw   rJ   c                 óH   — | j                  «       j                  t        «      S ©N)ÚlstripÚ
startswithr   rI   s    r7   Ú_is_pem_contentr|   œ   s   € Ø�<‰<‹>×$Ñ$¤[Ó1Ð1r6   Ú	directoryÚfilenameÚpemc                 ó  — t         j                  j                  | |«      }t        |dd¬«      5 }|j	                  |j                  d«      r|n|› d�«       d d d «       t        j                  |t        «       |S # 1 sw Y   Œ%xY w)NÚwzutf-8)Úencodingú
)rp   ÚpathÚjoinÚopenÚwriter<   Úchmodr   )r}   r~   r   r„   Úhandles        r7   Ú
_write_pemrŠ       so   € Ü—'‘'—,‘,˜y¨(Ó3€DÜ	ˆd�C 'Ô	*ð @¨fØ�‰˜CŸL™L¨Ô.‘S°s°e¸2°JÔ?÷@ä‡H�HˆT”>Ô"Ø€K÷@ð @ús   ¯(A;Á;BÚclient_certÚ
client_keyÚca_certc           	      óP  — t        d„ | ||fD «       «      }|st        | ||«      S t        j                  t        ¬«      }t        t        | «      rt        |t        | «      n| t        |«      rt        |t        |«      n||r!t        |«      rt        |t        |«      ¬«      S |¬«      S )a  
    Accept either a filesystem path or inline PEM content for each credential.

    Secret stores that inject values as environment content rather than mounted
    files (ECS tasks reading AWS Secrets Manager, Cloud Run reading Secret
    Manager) can only deliver the certificate as a string. The OTLP exporter
    takes paths, so inline PEM is written to a private directory once, when the
    recorder is built. Raises OSError if that write fails; the caller disables
    metering rather than propagating.
    c              3   ó>   K  — | ]  }|sŒt        |«      sŒ|–— Œ y ­wry   )r|   )Ú.0rJ   s     r7   ú	<genexpr>z,_resolve_credential_paths.<locals>.<genexpr>³   s   è ø€ Òt EÒSXÔ]lÐmrÕ]sœ%Ñtùs   ‚Š–)Úprefix)r)   r*   r+   )
Útuplerw   ÚtempfileÚmkdtempr   r|   rŠ   r   r    r!   )r‹   rŒ   r�   Úinliner}   s        r7   Ú_resolve_credential_pathsr—   ¨   s¬   € ô Ñt¨k¸:ÀwÐ-OÔtÓt€FÙÜ ¨Z¸ÓAÐAô  ×'Ñ'¬Ô?€IÜäIXÐYdÔIeŒJ�yÔ"7¸ÔEÐkvô HWÐWaÔGbŒJ�yÔ"6¸
ÔCÐhrñ BIÌ_Ð]dÔMeŒJ�yÔ"3°WÓ=ô
ð 
ð lsô
ð 
r6   Úlicense_datar   r-   c                 óÆ  — t        j                  t        «      }t        j                  t        «      }t        j                  t        «      }t        j                  t
        «      }t        |ft        |ft        |ffD ��cg c]	  \  }}|s|‘Œ }}}|r|r|s&t        j                  ddj                  |«      «       y 	 t        |||¬«      }	t        |	j                  ft        |	j                  ft
        |	j                  ffD ��cg c](  \  }}|r!t         j                  j                  |«      s|‘Œ* }}}|r+t        j                  ddj                  |«      t         «       y t#        ||	j                  |	j                  |	j                  t%        «       || xs i j'                  d«      ¬«      S c c}}w # t        $ r }
t        j                  d|
«       Y d }
~
y d }
~
ww xY wc c}}w )NzLEnterprise billing metrics disabled: licensed deployment missing config (%s)z, )r‹   rŒ   r�   z[Enterprise billing metrics disabled: could not write inline certificate content to disk: %szžEnterprise billing metrics disabled: %s did not resolve to a readable certificate file. Set each to a file path, or to inline PEM content beginning with '%s'.Úuser_id)r(   r)   r*   r+   r,   r-   r.   )rp   rq   r   r   r   r   r   rs   r…   r—   ÚOSErrorr)   r*   r+   r„   Úisfiler   r'   ru   Úget)r˜   r-   r(   r‹   rŒ   r�   r\   rJ   ÚmissingÚpathsÚexcÚenv_namer„   Ú
unreadables                 r7   Úload_billing_metrics_configr£   Æ   sÌ  € ô —i‘i¤Ó-€HÜŸ™¤?Ó3€KÜŸ	™	¤.Ó1€Jô —Y‘Yœ{Ó+€Gô
 ˜8Ð$Ü˜kÐ*Ü˜ZÐ(ð
÷áˆD�%ñ
 ò 	ð€Gñ ñ ™;©jÜ×$Ñ$ØZØ�I‰I�gÓô	
ð ðÜ0¸[ÐU_ÐipÔqˆô ˜e×4Ñ4Ð5Ü˜U×2Ñ2Ð3Ü˜%×,Ñ,Ð-ð
÷áˆH�dñ
 œŸ™Ÿ™ tÔ,ò 	ð€Jñ ñ Ü×$Ñ$ðUà�I‰I�jÓ!Üô		
ð äØØ×/Ñ/Ø×-Ñ-Ø×'Ñ'Ü.Ó0Ø'Ø Ò& B×+Ñ+¨IÓ6ôð ùó[øô$ ò Ü×$Ñ$ØiÐknô	
ô ûð	üós$   Á?F+Â=F1 Ä-GÆ1	GÆ:GÇGc                   ó:   — e Zd ZdZdd„Zdeddfd„Zdedz  fd„Zy)	Ú_ActiveRecorderRegistryz«One-slot registry linking the factory-built recorder to the shutdown
    hook; the middleware instance holding the recorder is not reachable from
    proxy_shutdown_event.r8   Nc                 ó   — d | _         y ry   ©Ú	_recorderrl   s    r7   rd   z _ActiveRecorderRegistry.__init__  s	   € Ø8<ˆ�r6   Úrecorderc                 ó   — || _         y ry   r§   ©rc   r©   s     r7   Úsetz_ActiveRecorderRegistry.set  s	   € Ø!ˆ�r6   c                 ó,   — | j                   }d | _         |S ry   r§   r«   s     r7   Úpopz_ActiveRecorderRegistry.pop  s   € ØŸ.™.ˆØˆŒØˆr6   rm   )r/   r0   r1   rn   rd   rY   r¬   r®   r5   r6   r7   r¥   r¥     s2   „ ñó=ð"Ð2ð "°tó "ðÐ+¨dÑ2ô r6   r¥   Ú_ACTIVE_RECORDERÚpremiumc                 óX  — | st        j                  d«       yt        ||¬«      }|€y	 t        t	        |«      «      }t        j                  |«       t        j                  d|j                  |j                  «       |S # t
        $ r }t        j                  d|«       Y d}~yd}~ww xY w)z\Build the recorder, or None when the deployment is not licensed or metering is unconfigured.z?Enterprise billing metrics disabled: deployment is not licensedN)r˜   r-   zFEnterprise billing metrics disabled: failed to initialize exporter: %sz?Enterprise billing metrics enabled: exporting to %s every %d ms)r   Údebugr£   rY   rW   Ú	Exceptionrs   r¯   r¬   Úinfor(   r,   )r°   r˜   r-   r?   r©   r    s         r7   Úbuild_billing_metrics_recorderrµ     s¦   € ñ ô 	×"Ñ"Ð#dÔeØä/¸\Ð[jÔk€FØ€~ØðÜ0Ô1JÈ6Ó1RÓSˆô ×Ñ˜Ô"ô ×ÑØIØ�‰Ø×!Ñ!ôð
 €Oøô ò Ü×$Ñ$Ð%mÐorÔsÜûðús   ªB  Â 	B)Â	B$Â$B)c                  ó¬   — t         j                  «       } | €y	 | j                  «        y# t        $ r }t	        j
                  d|«       Y d}~yd}~ww xY w)zEFlush and stop the active recorder, if any. Idempotent; never raises.Nz2Enterprise billing metrics: final flush failed: %s)r¯   r®   rk   r³   r   rs   )r©   r    s     r7   Ú!shutdown_billing_metrics_recorderr·   ;  sR   € ä&×*Ñ*Ó,€HØÐØð`Ø×ÑÕøÜò `Ü×$Ñ$Ð%YÐ[^×_Ñ_ûð`ús   ™* ª	A³AÁArm   )?rn   rp   r”   Údataclassesr   Útypingr   r   r   Ú6opentelemetry.exporter.otlp.proto.http.metric_exporterr   Úopentelemetry.metricsr   Úopentelemetry.sdk.metricsr	   Ú opentelemetry.sdk.metrics.exportr
   Úopentelemetry.sdk.resourcesr   Úlitellm._loggingr   Ú<litellm.proxy.middleware.billable_request_metrics_middlewarer   Úlitellm.proxy._typesr   r   r3   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r2   r4   ÚAttributeValuer'   r>   ÚdictrC   rL   rW   rY   ru   rw   Úboolr|   rŠ   r—   r£   r¥   r¯   rµ   r·   r5   r6   r7   ú<module>rÅ      s�  ðòó 
Û Ý !ß 1Ñ 1å UÝ )Ý 3Ý JÝ 0å 1õñ Ý:à8€ˆeÓ 8Ø>€�Ó >Ø<€�Ó <Ø6€ˆUÓ 6ØIÐ �UÓ IØ$*Ð ˜EÓ *Ø#(Ð ˜5Ó (Ø$€ˆuÓ $ð "€ˆUÓ !Ø0€�Ó 0Ø€�Ó Ø+Ð �uÓ +Ø*Ð �eÓ *Ø#Ð �5Ó #à;€ˆUÓ ;Ø0€
ˆEÓ 0à�s‘€ñ �$˜dÔ#÷ð ó $ððW ð W¨ó Wð$Ð!5ð $¸$¸sÀNÐ?RÑ:Só $ð	"Øð	"Ø'*ð	"Ø9<ð	"ØHKÈdÉ
ð	"à	ˆ#ˆ~Ð
Ñó	"ðjÐ&:ð j¸}ó j÷&Jñ Jð(
*˜Só 
*ñ �$˜dÔ#÷ð ó $ðð2˜3ð 2 4ó 2ð˜#ð ¨ð °3ð ¸3ó ð¨cð ¸sð ÈSÐSWÉZð Ð\ló ð<?ØÐ5Ñ6ð?ØILð?à˜DÑ ó?÷Dñ ñ" 2Ó3Ð �%Ó 3ðØðØ$,Ð-DÑ$EðØX[ðà˜dÑ"óô>`r6   