Ë
    tPêj$H  ã            
       ó¨  — U 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 ddl	m
Z
 ddlmZ ddlmZ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mZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z, ddl-m.Z.  e/ddh«      Z0ee1d<   de2dz  de2fd„Z3de.de*fd„Z4de5e*df   de5e'df   fd„Z6de5e*df   de7de7de5e)df   fd„Z8 G d„ de«      Z9y)aß  
New Relic Metric API Integration - sends per-team cost/usage metrics to /metric/v1

NR Reference API: https://docs.newrelic.com/docs/data-apis/ingest-apis/metric-api/introduction-metric-api/

`async_log_success_event` / `async_log_failure_event` queue one record per request;
at flush the queue is aggregated by (team, model group, model, provider, status)
into count/summary metrics. `interval.ms` is the real window between flushes,
computed at flush time.

Team-scoped by construction: the ingest key is injected explicitly and there is
deliberately no environment-variable fallback, so a team's metrics are never sent
with the proxy operator's credentials (mirrors ``allow_env_credentials=False`` on
the Datadog team logger).

Error policy on flush: 4xx drops the batch (a retry would fail identically; 403
is a permanent credential failure), 5xx/network re-queues capped at
``max_queue_size`` records with the oldest dropped.

For batching specific details see CustomBatchLogger class
é    N)ÚMapping)Úceil)ÚMappingProxyType)ÚFinal)ÚHTTPStatusErrorÚResponse)Úverbose_logger)ÚCustomBatchLogger)Ú
safe_dumps)Úget_async_httpx_clientÚhttpxSpecialProvider)ÚNEWRELIC_DEFAULT_REGIONÚ!NEWRELIC_METRIC_ATTRIBUTE_MAX_LENÚ!NEWRELIC_METRIC_COMPLETION_TOKENSÚNEWRELIC_METRIC_COST_USDÚ"NEWRELIC_METRIC_ENDPOINT_BY_REGIONÚNEWRELIC_METRIC_PROMPT_TOKENSÚ#NEWRELIC_METRIC_REQUEST_DURATION_MSÚNEWRELIC_METRIC_REQUESTSÚNEWRELIC_METRIC_TOTAL_TOKENSÚNEWRELIC_METRICS_MAX_BATCH_SIZEÚ!NEWRELIC_METRICS_MAX_DRAIN_PASSESÚ%NEWRELIC_METRICS_MAX_RETRY_QUEUE_SIZEÚNewRelicCountMetricÚNewRelicMetricÚNewRelicMetricCommonÚNewRelicMetricEnvelopeÚNewRelicMetricRecordÚNewRelicSummaryMetricÚNewRelicSummaryValue)ÚStandardLoggingPayloadi˜  i­  Ú_RETRYABLE_CLIENT_STATUSESÚnewrelic_regionÚreturnc           	      óî   — | st         t           S t        j                  | j                  «       «      }|€@t	        j
                  d| dj                  t        t         «      «      «       t         t           S |S )Nz^New Relic: unknown newrelic_region %r; supported regions: %s. Using the default (US) endpoint.z, )r   r   ÚgetÚlowerr	   ÚwarningÚjoinÚsorted)r#   Úendpoints     ús/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/newrelic/newrelic_metrics.pyÚ resolve_newrelic_metric_endpointr-   E   si   € ÙÜ1Ô2IÑJÐJÜ8×<Ñ<¸_×=RÑ=RÓ=TÓU€HØÐÜ×ÑØlØØ�I‰I”fÔ?Ó@ÓAô	
ô
 2Ô2IÑJÐJØ€Oó    Ústandard_logging_objectc                 óÈ  — | j                  d«      }|r$|j                  d«      xs |j                  d«      nd xs d}|r$|j                  d«      xs |j                  d«      nd xs d}t        ||| j                  d«      xs d| j                  d«      xs d| j                  d	«      xs dt        | j                  d
«      xs d«      t        | j                  d«      xs d«      t	        | j                  d«      xs d«      t	        | j                  d«      xs d«      t	        | j                  d«      xs d«      t        | j                  d«      xs d«      dz  ¬«      S )NÚmetadataÚuser_api_key_team_idÚteam_idÚ Úuser_api_key_team_aliasÚ
team_aliasÚmodel_groupÚmodelÚcustom_llm_providerÚstatusÚsuccessÚresponse_costg        Úprompt_tokensr   Úcompletion_tokensÚtotal_tokensÚresponse_timeg     @�@)r3   r6   r7   r8   r9   r:   r<   r=   r>   r?   Úduration_ms)r&   r   ÚstrÚfloatÚint)r/   r1   r3   r6   s       r,   Ú_metric_record_from_payloadrE   S   sU  € Ø-×1Ñ1°*Ó=€HÙ[c�x—|‘|Ð$:Ó;ÒV¸x¿|¹|ÈIÔ?VÐimÒtÐrt€GáS[ˆ�‰Ð/Ó	0Ò	N°H·L±LÀÔ4NÐaeòà	ð ô  ØØØ+×/Ñ/°Ó>ÒDÀ"Ø%×)Ñ)¨'Ó2Ò8°bØ3×7Ñ7Ð8MÓNÒTÐRTÜÐ*×.Ñ.¨xÓ8ÒE¸IÓFÜÐ3×7Ñ7¸ÓHÒOÈCÓPÜÐ1×5Ñ5°oÓFÒKÈ!ÓLÜÐ5×9Ñ9Ð:MÓNÒSÐRSÓTÜÐ0×4Ñ4°^ÓDÒIÈÓJÜÐ1×5Ñ5°oÓFÒMÈ#ÓNÐQWÑWôð r.   Úbucket_records.c                 óú  ‡— | d   }d|j                   fd|j                  fd|j                  fd|j                  fd|j                  fd|j
                  ffD ��ci c]  \  }}|r
||d t         “Œ c}}Št        d„ | D «       «      }t        t        t        | «      «      ft        t        d	„ | D «       «      ft        t        t        d
„ | D «       «      «      ft        t        t        d„ | D «       «      «      ft        t        t        d„ | D «       «      «      ff}t        ˆfd„|D «       «      }t!        t"        dt%        t        |«      t        |«      t'        |«      t)        |«      ¬«      ‰¬«      }g |¢|‘­S c c}}w )Nr   r3   r6   r7   r8   r9   r:   c              3   ó4   K  — | ]  }|j                   –— Œ y ­w©N)rA   ©Ú.0Úrecords     r,   ú	<genexpr>z"_bucket_metrics.<locals>.<genexpr>v   s   è ø€ ÒM°F˜V×/Õ/ÑMùó   ‚c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrI   )r<   rJ   s     r,   rM   z"_bucket_metrics.<locals>.<genexpr>y   s   è ø€ Ò&YÀ v×';Õ';Ñ&YùrN   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrI   )r=   rJ   s     r,   rM   z"_bucket_metrics.<locals>.<genexpr>z   s   è ø€ Ò1dÈ6°&×2FÕ2FÑ1dùrN   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrI   )r>   rJ   s     r,   rM   z"_bucket_metrics.<locals>.<genexpr>{   s   è ø€ Ò5lÐSY°f×6NÕ6NÑ5lùrN   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrI   )r?   rJ   s     r,   rM   z"_bucket_metrics.<locals>.<genexpr>|   s   è ø€ Ò0bÈ°×1DÕ1DÑ0bùrN   c              3   óB   •K  — | ]  \  }}t        |d |‰¬«      –— Œ y­w)Úcount©ÚnameÚtypeÚvalueÚ
attributesN)r   )rK   rV   rX   rY   s      €r,   rM   z"_bucket_metrics.<locals>.<genexpr>~   s+   øè ø€ ò =Ù]hÐ]aÐchÔ ¨G¸5ÈZ×XÐXñ=ùó   ƒÚsummary)rT   ÚsumÚminÚmaxrU   )r3   r6   r7   r8   r9   r:   r   Útupler   rC   Úlenr   r\   r   r   r   r   r   r    r]   r^   )	rF   ÚfirstÚkeyrX   Ú	durationsÚcountsÚcount_metricsÚsummary_metricrY   s	           @r,   Ú_bucket_metricsrg   h   sƒ  ø€ Ø! !Ñ$€Eð ˜Ÿ™Ð&Ø˜5×+Ñ+Ð,Ø˜E×-Ñ-Ð.Ø�e—k‘kÐ"Ø" E×$=Ñ$=Ð>Ø�u—|‘|Ð$ð
÷,áˆC�ñ ð 	ˆUÐ5Ô5Ð6Ñ6ó,€Jô ÑM¸nÔMÓM€Iä	!¤5¬¨^Ó)<Ó#=Ð>Ü	!¤3Ñ&YÈ.Ô&YÓ#YÐZÜ	&¬¬cÑ1dÐUcÔ1dÓ.dÓ(eÐfÜ	*¬E´#Ñ5lÐ]kÔ5lÓ2lÓ,mÐnÜ	%¤u¬SÑ0bÐSaÔ0bÓ-bÓ'cÐdð4€Fô 8=ó =Ølrô=ó 8€Mô 2Ü0ØÜ"Ü�i“.Ü�I“Ü�I“Ü�I“ô	
ð ô
€Nð ,ˆ]Ð+˜NÑ+Ð+ùóE,s   ÁE7ÚrecordsÚwindow_startÚnowc                óê   ‡ — t        dt        ||z
  dz  «      «      }t        t        j	                  d„ ‰ D «       «      «      }t        ˆ fd„|D «       «      }t        |dz  «      |dœ}t        ||¬«      fS )zEAggregates records into one Metric API envelope for the flush window.é   iè  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrI   ©Ú
bucket_keyrJ   s     r,   rM   z'build_metric_payload.<locals>.<genexpr>—   s   è ø€ Ò,UÀ6¨V×->Õ->Ñ,UùrN   c              3   óh   •‡K  — | ](  Št        t        ˆfd „‰D «       «      «      D ]  }|–— Œ Œ* y­w)c              3   óB   •K  — | ]  }|j                   ‰k(  sŒ|–— Œ y ­wrI   rn   )rK   rL   rb   s     €r,   rM   z1build_metric_payload.<locals>.<genexpr>.<genexpr>›   s   øè ø€ Ò+e°vÈF×L]ÑL]ÐadÓLd¬FÑ+eùs   ƒ˜N)rg   r_   )rK   Úmetricrb   rh   s     @€r,   rM   z'build_metric_payload.<locals>.<genexpr>˜   s>   ùè ø€ ò àÜ%¤eÓ+eÀÔ+eÓ&eÓfòð ô 	ðØñùs   „.2)Ú	timestampzinterval.ms)ÚcommonÚmetrics)r^   rD   r_   ÚdictÚfromkeysr   )rh   ri   rj   Úinterval_msÚbucket_keysru   rt   s   `      r,   Úbuild_metric_payloadrz   �   s{   ø€ ô ˜Q¤ S¨<Ñ%7¸4Ñ$?Ó @ÓA€KÜœtŸ}™}Ñ,UÈWÔ,UÓUÓV€KÜó àôó €Gô ˜¨Ñ,Ó-Ø"ñ+€Fô #¨&¸'ÔBÐDÐDr.   c                   óö   ‡ — e Zd Z	 ddededz  ddfˆ fd„Zdd„Zdd„Zdd„Zdd	„Zdd
„Z	dd„Z
dd„Zdedz  ddfd„Zdd„Zddedz  defd„Zdeedf   dedefd„Zdeedf   ddfd„Zdeedf   defd„Zˆ xZS )ÚNewRelicMetricsLoggerNÚnewrelic_api_keyr#   r$   c                 óŒ  •— |st        d«      ‚|| _        t        |«      | _        t	        t
        j                  ¬«      | _        d| _        t        j                  «       | _        t        j                  | j                  «       «       t        j                  «       | _        t        ‰| �A  | j                  t"        t$        ¬«       y )Nzvnewrelic_api_key is required for NewRelicMetricsLogger; team-scoped metrics never fall back to environment credentials)Úllm_providerF)Ú
flush_lockÚ
batch_sizeÚmax_queue_size)Ú
ValueErrorr}   r-   Úmetric_api_urlr   r   ÚLoggingCallbackÚasync_clientÚ_stoppedÚasyncioÚLockÚ_drain_lockÚcreate_taskÚperiodic_flushr€   ÚsuperÚ__init__r   r   )Úselfr}   r#   Ú	__class__s      €r,   rŽ   zNewRelicMetricsLogger.__init__¥   sž   ø€ ñ
  ÜðQóð ð (8ˆÔÜ%EÀoÓ%VˆÔÜ2Ô@T×@dÑ@dÔeˆÔØ#ˆŒÜ"Ÿ<™<›>ˆÔÜ×Ñ˜D×/Ñ/Ó1Ô2Ü!Ÿ,™,›.ˆŒÜ‰ÑØ—‘Ü6Ü@ð 	õ 	
r.   c                 óÂ   — d| _         	 t        j                  «       j                  | j	                  «       «       y# t
        $ r t        j                  dd¬«       Y yw xY w)a  Ends the periodic flush loop; called on DynamicLoggingCache eviction.

        Schedules one final drain of anything still queued, so eviction never
        silently discards records. Guarded so it can never raise into the
        cache's eviction path.
        Tz;New Relic Metrics: could not schedule final drain on stop())Úexc_infoN)r‡   rˆ   Úget_running_loopr‹   Ú_final_drainÚ	Exceptionr	   Údebug©r�   s    r,   ÚstopzNewRelicMetricsLogger.stop¼   sT   € ð ˆŒð	oÜ×$Ñ$Ó&×2Ñ2°4×3DÑ3DÓ3FÕGøÜò 	oÜ× Ñ Ð!^Ðim×nð	oús   ‰1; » AÁAc              ƒ   ó:  ‡K  — | j                   4 ƒd{  –—†  t        | j                  «      }t        t        «      D ]e  }| j                  «       ƒ d{  –—†  | j                  s ddd«      ƒd{  –—†  y|t        dz
  k  sŒFt        j                  d|z  «      ƒ d{  –—†  Œg | j                  4 ƒd{  –—†  t        d„ |D «       «      Št        ˆfd„| j                  D «       «      }t        | j                  «      t        |«      z
  }|rt        j                  d|t        «       t        |«      | j                  dd ddd«      ƒd{  –—†  ddd«      ƒd{  –—†  y7 �ŒM7 �Œ7 Œö7 ŒÊ7 Œµ7 Œ!# 1 ƒd{  –—†7  sw Y   Œ1xY w7 Œ(# 1 ƒd{  –—†7  sw Y   yxY w­w)aÙ  Deliver everything queued on a stopped logger, or drop it with a log.

        A stopped logger has no periodic loop left, so every post-stop path
        funnels through here. ``_drain_lock`` serializes drains: a callback that
        appends and starts its own drain queues behind the running one instead
        of racing it. Each pass attempts the whole current queue in
        ``batch_size`` chunks, unlike the periodic path it does not stop at the
        first failing chunk, so a persistently failing head never starves the
        tail. Only after ``_MAX_DRAIN_PASSES`` against a permanently failing
        destination is the remainder dropped, and then only the records that were
        queued when this drain began, so every dropped record got the full retry
        budget: a record a callback appended mid-drain is not in that snapshot,
        so it is left for its own serialized drain rather than dropped after
        fewer attempts, and is never stranded.
        Nrl   é   c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wrI   ©ÚidrJ   s     r,   rM   z:NewRelicMetricsLogger._drain_with_retry.<locals>.<genexpr>â   s   è ø€ Ò,P¸F¬R°¯ZÑ,Pùs   ‚c              3   ó>   •K  — | ]  }t        |«      ‰vsŒ|–— Œ y ­wrI   rœ   )rK   rL   Ú	tried_idss     €r,   rM   z:NewRelicMetricsLogger._drain_with_retry.<locals>.<genexpr>ã   s    øè ø€ Ò(l°FÔPRÐSYÓPZÐbkÒPk¬Ñ(lùs   ƒ–z<New Relic Metrics: dropping %s records after %s drain passes)rŠ   r_   Ú	log_queueÚranger   Ú_drain_flush_oncerˆ   Úsleepr€   Ú	frozensetr`   r	   r(   Úlist)r�   Ú	attemptedÚ_passÚ	survivorsÚdroppedrŸ   s        @r,   Ú_drain_with_retryz'NewRelicMetricsLogger._drain_with_retryÉ   si  øè ø€ ð  ×#Ñ#÷ 	4ñ 	4Ü$ T§^¡^Ó4ˆIÜÔ@ÓAò 2�Ø×,Ñ,Ó.×.Ð.Ø—~’~Ø÷	4÷ 	4ð 	4ð Ô<¸qÑ@Ó@Ü!Ÿ-™-¨¨5©Ó1×1Ñ1ð2ð —‘÷ 
4ñ 
4Ü#,Ñ,PÀiÔ,PÓ#P�	Ü#(Ó(l¸d¿n¹nÔ(lÓ#l�	Ü!$ T§^¡^Ó!4´s¸9³~Ñ!E�ÙÜ"×*Ñ*ØVØÜ9ôô
 %)¨£O�—‘™qÐ!÷
4÷ 
4÷	4÷ 	4ñ 	4ùð /ùð	4øð 2øð
4øð 
4ø÷ 
4÷ 
4ñ 
4úð	4ø÷ 	4÷ 	4ñ 	4üsÕ   ƒF”E!•F˜;FÁE$ÁFÁ%FÁ0E'Á1FÁ6FÂFÂE)ÂFÂ5E+Â6FÂ9BE/Å FÅE-ÅFÅFÅFÅFÅ$FÅ'FÅ)FÅ+FÅ-FÅ/F	Å5E8Å6F	Å=FÆFÆFÆFÆFÆFc           	   ƒ   óZ  ‡ ‡K  — ‰ j                   4 ƒd{  –—†  t        ‰ j                  «      Š‰ j                  }t	        j                  «       ‰ _        ‰ j                  dd…= ddd«      ƒd{  –—†  ‰syt        ˆˆ fd„t        dt        ‰«      ‰ j                  «      D «       «      }t        |D �cg c]  }‰ j                  |«      ƒ d{  –—† ‘Œ c}«      }t        d„ t        ||«      D «       «      }|r‰ j                  |«       yy7 Œõ7 Œž# 1 ƒd{  –—†7  sw Y   Œ®xY w7 ŒWc c}w ­w)a¿  Attempt every queued record once, in ``batch_size`` chunks, without
        stopping at the first failing chunk so a persistently failing head does
        not starve the tail (the periodic ``flush_queue`` deliberately stops
        instead). Takes the queue under ``flush_lock`` and re-queues only the
        chunks a 5xx/network error left undelivered, so records a concurrent
        request appends during the sends survive for the next pass.Nc              3   óB   •K  — | ]  }‰||‰j                   z    –— Œ y ­wrI   )r�   )rK   ÚstartÚpendingr�   s     €€r,   rM   z:NewRelicMetricsLogger._drain_flush_once.<locals>.<genexpr>û   s&   øè ø€ ò 
Ø9>ˆG�E˜E D§O¡OÑ3Ô4ñ
ùrZ   r   c              3   ó<   K  — | ]  \  }}|rd n|D ]  }|–— Œ Œ y­w)© Nr°   )rK   ÚchunkÚokrL   s       r,   rM   z:NewRelicMetricsLogger._drain_flush_once.<locals>.<genexpr>ÿ   s(   è ø€ Òq©¨°ÑbdÑ\^ÐjoÒqÐQWœfÐq˜fÑqùs   ‚)r€   r_   r    Úlast_flush_timeÚtimer¡   r`   r�   Ú_classify_and_sendÚzipÚ_requeue)r�   ri   Úchunksr±   Ú	deliveredÚfailedr®   s   `     @r,   r¢   z'NewRelicMetricsLogger._drain_flush_onceí   s  ùè ø€ ð —?‘?÷ 	"ñ 	"Ü" 4§>¡>Ó2ˆGØ"&×"6Ñ"6ˆLÜ#'§9¡9£;ˆDÔ Ø—‘šqÐ!÷		"÷ 	"ñ
 ØÜô 
ÜBGÈÌ3ÈwË<ÐY]×YhÑYhÓBiô
ó 
ˆô !ÐbhÖ!iÐY^¨×(?Ñ(?ÀÀ|Ó(T×"TÑ"TÒ!iÓjˆ	ÜÑq´c¸&À)Ó6LÔqÓqˆÙØ�M‰M˜&Õ!ð ð	"øð 	"ø÷ 	"÷ 	"ñ 	"úð #UúÒ!iùsj   „D+•D–D+™A
DÁ#D+Á.DÁ/AD+Â2D&ÃD$ÃD&Ã9D+ÄD+ÄD!ÄDÄD!ÄD+Ä$D&Ä&D+c              ƒ   ó@   K  — | j                  «       ƒ d {  –—†  y 7 Œ­wrI   )rª   r—   s    r,   r”   z"NewRelicMetricsLogger._final_drain  s   è ø€ Ø×$Ñ$Ó&×&Ò&ús   ‚–—c              ƒ   ó  K  — | j                   sYt        j                  | j                  «      ƒ d {  –—†  | j                   rn%| j	                  «       ƒ d {  –—†  | j                   sŒY| j                  «       ƒ d {  –—†  y 7 ŒO7 Œ,7 Œ	­wrI   )r‡   rˆ   r£   Úflush_intervalÚflush_queuer”   r—   s    r,   rŒ   z$NewRelicMetricsLogger.periodic_flush  sm   è ø€ Ø—-’-Ü—-‘- × 3Ñ 3Ó4×4Ð4Ø�}Š}ØØ×"Ñ"Ó$×$Ð$ð	 —-“-ð
 ×ÑÓ!×!Ñ!ð	 5øð %øØ!ús9   ‚/B±B²$BÁBÁBÁ(BÁ;BÁ<BÂBÂBc              ƒ   óä   K  — 	 | j                  |j                  dd «      ¬«      ƒ d {  –—†  y 7 Œ# t        $ r3}t        j                  d|t        j                  «       «       Y d }~y d }~ww xY w­w©Nr/   )r/   z%New Relic Metrics Layer Error - %s
%s©Ú_log_async_eventr&   r•   r	   Ú	exceptionÚ	tracebackÚ
format_exc©r�   ÚkwargsÚresponse_objÚ
start_timeÚend_timeÚes         r,   Úasync_log_success_eventz-NewRelicMetricsLogger.async_log_success_event  óa   è ø€ ð	jØ×'Ñ'ÀÇ
Á
ÐKdÐfjÓ@kÐ'Ól×lÒlùÜò 	jÜ×$Ñ$Ð%MÈqÔR[×RfÑRfÓRh×iÑiûð	jüó6   ‚A0„%1 ©/ª1 ®A0¯1 ±	A-º)A(Á#A0Á(A-Á-A0c              ƒ   óä   K  — 	 | j                  |j                  dd «      ¬«      ƒ d {  –—†  y 7 Œ# t        $ r3}t        j                  d|t        j                  «       «       Y d }~y d }~ww xY w­wrÀ   rÁ   rÆ   s         r,   Úasync_log_failure_eventz-NewRelicMetricsLogger.async_log_failure_event  rÍ   rÎ   r/   c              ƒ   ó6  K  — |€t        d«      ‚| j                  j                  t        |«      «       | j                  r| j                  «       ƒ d {  –—†  y t        | j                  «      | j                  k\  r| j                  «       ƒ d {  –—†  y y 7 ŒA7 Œ­w)Nz+standard_logging_object not found in kwargs)	rƒ   r    ÚappendrE   r‡   rª   r`   r�   r¾   )r�   r/   s     r,   rÂ   z&NewRelicMetricsLogger._log_async_event  s†   è ø€ Ø"Ð*ÜÐJÓKÐKØ�‰×ÑÔ9Ð:QÓRÔSØ�=Š=ð ×(Ñ(Ó*×*Ð*ØÜˆt�~‰~Ó $§/¡/Ò1Ø×"Ñ"Ó$×$Ñ$ð 2ð +øð %ús$   ‚ABÁBÁ:BÂBÂBÂBc              ƒ   ó   K  — | j                   4 ƒd {  –—†  | j                  }t        j                  «       | _        t        | j                  «      }|s	 d d d «      ƒd {  –—†  y t        j                  d|«       t        t        || j                  z  «      «      D ].  }| j                  |¬«      ƒ d {  –—† rŒ d d d «      ƒd {  –—†  y  d d d «      ƒd {  –—†  y 7 ŒË7 Œ€7 Œ-7 Œ7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)Nz-New Relic Metrics: Flushing %s queued records)ri   )r€   r³   r´   r`   r    r	   r–   r¡   r   r�   Úasync_send_batch)r�   ri   ÚqueuedÚ_chunks       r,   r¾   z!NewRelicMetricsLogger.flush_queue&  sì   è ø€ Ø—?‘?÷ 	ñ 	Ø"&×"6Ñ"6ˆLÜ#'§9¡9£;ˆDÔ Ü §¡Ó/ˆFÙØ÷	÷ 	ð 	ô × Ñ Ð!PÐRXÔYô  ¤ V¨d¯o©oÑ%=Ó >Ó?ò �Ø!×2Ñ2ÀÐ2ÓM×MÑMØ÷	÷ 	ð 	ð÷	÷ 	ñ 	øð 	øð Nøð	øð 	ø÷ 	÷ 	ñ 	üs™   ‚C>“C”C>—>C)ÁC>Á C!Á!C>Á&AC)Â5C#Â6C)Â;C)Â<C>ÃC%ÃC>ÃC)ÃC>ÃC'ÃC>Ã!C>Ã#C)Ã%C>Ã'C>Ã)C;Ã/C2Ã0C;Ã7C>ri   c              ƒ   ó  K  — | j                   syt        | j                   d| j                   «      }| j                   dt        |«      …= | j	                  ||�|n| j
                  «      ƒ d{  –—† }|s| j                  |«       |S 7 Œ­w)zéSends the oldest ``batch_size`` records only, so a queue grown past that
        by re-queues cannot breach the Metric API data point cap in one request.
        Returns False once a chunk fails and is re-queued, so the caller stops.FN)r    r_   r�   r`   rµ   r³   r·   )r�   ri   Úbatch_to_sendr¹   s       r,   rÔ   z&NewRelicMetricsLogger.async_send_batch4  s‰   è ø€ ð �~Š~ØäAFÀtÇ~Á~ÐVgÐX\×XgÑXgÐGhÓAiˆØ�N‰NÐ/œS Ó/Ð/Ð0à!%×!8Ñ!8Ø¨<Ð+C™<È×I]ÑI]ó"
÷ 
ˆ	ñ Ø�M‰M˜-Ô(ØÐð
ús   ‚A+B	Á-BÁ.B	Úbatch.c              ƒ   ó*  K  — t        ||t        j                  «       ¬«      }	 | j                  |«      ƒ d{  –—† j                  }d|cxk  rdk  ry d|cxk  rd	k  r4n n1|t        vr)t        j                  d
||dk(  rdndt        |«      «       yt        j                  d|t        |«      «       y7 Œ{# t        $ r }|j
                  j                  }Y d}~Œ“d}~wt        $ r*}t        j                  dt        |«      |«       Y d}~yd}~ww xY w­w)a!  Send one chunk and classify the outcome, never touching the queue.
        Returns True when the batch is done with (delivered on any 2xx, or a 4xx
        a retry would only repeat, 403 being a permanent bad-key rejection), and
        False when a 5xx or network error means the caller should re-queue it.

        ``AsyncHTTPHandler.post`` raises ``HTTPStatusError`` on any non-2xx, so a
        4xx never returns a response here; the status is read off the raised
        error to keep the client-error path (drop) distinct from 5xx (retry).)rh   ri   rj   NzDNew Relic Metrics: network error sending %s records, will retry - %sFéÈ   i,  Ti�  iô  z=New Relic Metrics: %s from Metric API%s, dropping %s records.i“  zC (permanent credential failure: invalid or revoked team ingest key)r4   z<New Relic Metrics: %s from Metric API, will retry %s records)rz   r´   Úasync_send_compressed_dataÚstatus_coder   Úresponser•   r	   r(   r`   r"   )r�   rÙ   ri   Úpayloadr:   rË   s         r,   rµ   z(NewRelicMetricsLogger._classify_and_sendE  s	  è ø€ ô .°eÈ,Ô\`×\eÑ\eÓ\gÔhˆð	à×5Ñ5°gÓ>×>ß‰kð ð �&Ô˜3ÒØð ð �&Ô˜3Õ 6Ô1KÑ#KÜ×"Ñ"ØOØØY_ÐcfÒYfÑUÐlnÜ�E“
ô	ð ä×ÑØJØÜ�‹Jô	
ð
 ð; ?ùäò 	,Ø—Z‘Z×+Ñ+�FûÜò 	Ü×"Ñ"ØVÜ�E“
Øôô
 ûð	üsQ   ‚!D¤B6 ¸B4¹B6 ÁA-DÂ4B6 Â6	DÂ?CÃDÃDÃ& DÄDÄDÄDc                 óÒ   — || j                   dd t        | j                   «      | j                  z
  }|dkD  r1| j                   d|…= t        j                  d| j                  |«       yy)zÖPrepends ``batch`` in place (never by assignment: records appended by
        concurrent requests during the flush await must survive), keeping
        chronological order so the cap drops the oldest records first.Nr   zUNew Relic Metrics: retry queue exceeded max_queue_size=%s; dropped %s oldest records.)r    r`   r‚   r	   r(   )r�   rÙ   Úoverflows      r,   r·   zNewRelicMetricsLogger._requeuep  sf   € ð #ˆ�‰�r˜ÐÜ˜dŸn™nÓ-°×0CÑ0CÑCˆØ�aŠ<Ø—‘˜y ˜yÐ)Ü×"Ñ"ØgØ×#Ñ#Øõð r.   rß   c              ƒ   óú   K  — t        j                  t        |«      j                  d«      «      }t	        dd| j
                  dœ«      }| j                  j                  | j                  ||¬«      ƒ d {  –—† S 7 Œ­w)Nzutf-8zapplication/jsonÚgzip)zContent-TypezContent-EncodingzApi-Key)ÚurlÚdataÚheaders)	rã   Úcompressr   Úencoder   r}   r†   Úpostr„   )r�   rß   Úcompressed_dataræ   s       r,   rÜ   z0NewRelicMetricsLogger.async_send_compressed_data~  s{   è ø€ Ü!%§¡¬z¸'Ó/B×/IÑ/IÈ'Ó/RÓ!SˆÜ,<à 2Ø$*Ø×0Ñ0ñó-
ˆð ×&Ñ&×+Ñ+Ø×#Ñ#Ø Øð ,ó 
÷ 
ð 	
ð 
ús   ‚A2A;Á4A9Á5A;rI   )r$   N)Ú__name__Ú
__module__Ú__qualname__rB   rŽ   r˜   rª   r¢   r”   rŒ   rÌ   rÐ   r!   rÂ   r¾   rC   ÚboolrÔ   r_   r   rµ   r·   r   r   rÜ   Ú__classcell__)r�   s   @r,   r|   r|   ¤   sñ   ø„ ð '+ñ
àð
ð ˜t™ð
ð 
õ	
ó.oó"4óH"ó,'ó"ójójð
%Ð>TÐW[Ñ>[ð 
%Ð`dó 
%óñ°5¸4±<ð È4ó ð")¨eÐ4HÈ#Ð4MÑ.Nð )Ð^cð )Ðhló )ðV˜eÐ$8¸#Ð$=Ñ>ð À4ó ð
¸Ð>TÐVYÐ>YÑ8Zð 
Ð_g÷ 
r.   r|   ):Ú__doc__rˆ   rã   r´   rÄ   Úcollections.abcr   Úmathr   Útypesr   Útypingr   Úhttpxr   r   Úlitellm._loggingr	   Ú(litellm.integrations.custom_batch_loggerr
   Ú*litellm.litellm_core_utils.safe_json_dumpsr   Ú&litellm.llms.custom_httpx.http_handlerr   r   Ú#litellm.types.integrations.newrelicr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    Úlitellm.types.utilsr!   r¤   r"   Ú__annotations__rB   r-   rE   r_   rg   rC   rz   r|   r°   r.   r,   ú<module>rý      s  ðòó, Û Û Û Ý #Ý Ý "Ý ç +å +Ý FÝ A÷÷÷ ÷ ÷ ÷ ñ õ* 7ñ %.¨s°C¨jÓ$9Ð ˜EÓ 9ð°c¸D±jð ÀSó ðÐ9Oð ÐThó ð*$, EÐ*>ÀÐ*CÑ$Dð $,ÈÈ~Ð_bÐObÑIcó $,ðNEØÐ'¨Ð,Ñ-ðEð ðEð 
ð	Eð
 Ð! 3Ð&Ñ'óEô*g
Ð-õ g
r.   