
    Pmj                        U d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	m
Z
  ej        e          ZdZdZ G d d          Zdad	ed
<    ej                    ZddZddZdddZeZg dZdS )u  Monitoring emitter: fire-and-forget queue + background dispatcher.

The emitter is the single seam between producers (gateway status hooks, the
diagnostic log handler) and consumers (the OTLP streamers). Its contract is
the hot-path invariant:

    ``emit()`` MUST return in O(microseconds), MUST NOT block on disk/network,
    and MUST NEVER raise into the caller. A monitoring failure is logged
    locally and dropped — it can never affect the gateway or a session.

Mechanism:
  * ``emit(event)`` does a non-blocking ``queue.put_nowait`` wrapped in a bare
    except. On a full queue it drops the *oldest* event and counts the drop.
  * A daemon thread drains the queue and fans each batch out to subscribers
    (the OTLP metric/span/log streamers). Each subscriber is fail-isolated —
    a slow or raising subscriber never affects the hot path or its peers.

Nothing is persisted here. Monitoring is an egress path, not a local store;
if no subscriber is attached, events simply age out of the ring buffer.
    )annotationsN)AnyDictOptionali'     c                  j    e Zd ZdZddddZddZddZddZddZddZ	ddZ
dddZddZddZdS )MonitoringEmitterz?Owns the queue, the dispatcher thread, and the subscriber list.Tenabledr   boolreturnNonec                   || _         t          j        t                    | _        d| _        d| _        t          j                    | _	        d| _
        t          j                    | _        d | _        g | _        d S )N)maxsizer   F)_enabledqueueQueue
_MAX_QUEUE_q_dropped_dispatched	threadingEvent_stop_startedLock_lock_thread_subscribers)selfr   s     >/home/thesage/.hermes/hermes-agent/agent/monitoring/emitter.py__init__zMonitoringEmitter.__init__'   sh    16Z1P1P1P_&&
^%%
37 #%    eventr   c                   | j         sdS 	 t          |d          r|                                nt          |          }|                    dt          j                               |                                  	 | j        	                    |           dS # t          j        $ r 	 | j                                         | j                                         | xj        dz  c_        | j        	                    |           n # t          $ r | xj        dz  c_        Y nw xY wY dS Y dS w xY w# t          $ r  t                               dd           Y dS w xY w)zEnqueue an event. Never blocks, never raises.

        ``event`` may be a dataclass with ``to_dict()`` or a plain dict.
        Nto_dictts_ns   zmonitoring emit failedTexc_info)r   hasattrr&   dict
setdefaulttimetime_ns_ensure_startedr   
put_nowaitr   Full
get_nowait	task_doner   	Exceptionloggerdebug)r    r$   payloads      r!   emitzMonitoringEmitter.emit5   s   
 } 	F	B)0	)B)BSemmoooUGw777  """
'""7+++++: ' ' ''G&&(((G%%'''MMQ&MMG&&w////  ' ' 'MMQ&MMMM' 0//!MM'  	B 	B 	BLL1DLAAAAAA	Bs[   A.D- :B D*&ADD*D D*D  D*#D- &D- )D**D- -&EEc                   | j         rd S | j        5  | j         r	 d d d            d S t          j        | j        dd          | _        | j                                         d| _         d d d            d S # 1 swxY w Y   d S )Nzhermes-monitoring-dispatchTtargetnamedaemon)r   r   r   Thread_runr   startr    s    r!   r0   z!MonitoringEmitter._ensure_startedO   s    = 	FZ 	! 	!} 	! 	! 	! 	! 	! 	! 	! 	! %+y'CD  DL L    DM	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!s   	A5AA55A9<A9c                r   | j                                         s	 | j                            d          }n# t          j        $ r Y Hw xY w|g}t          |          t          k     r[	 |                    | j        	                                           n# t          j        $ r Y nw xY wt          |          t          k     [	 | 
                    |           |D ]}| j                                         n## |D ]}| j                                         w xY w| j                                         d S d S )Ng      ?timeout)r   is_setr   getr   Emptylen_DRAIN_BATCHappendr3   	_dispatchr4   )r    firstbatch_s       r!   r@   zMonitoringEmitter._run[   sg   *##%% 	(C00;   GEe**|++LL!3!3!5!56666{   E e**|++
(u%%% ( (AG%%''''( ( (AG%%''''( *##%% 	( 	( 	( 	( 	(s-   8 A
	A
),B B('B(C8 8 Dc                    t          | j                  D ]:}	  ||           # t          $ r t                              dd           Y 7w xY w| xj        t          |          z  c_        d S )Nzmonitoring subscriber failedTr)   )listr   r5   r6   r7   r   rI   )r    rN   subs      r!   rL   zMonitoringEmitter._dispatchm   s    )** 	L 	LCLE



 L L L;dKKKKKLCJJ&s   $&AAc                Z    || j         vr| j                             |           d| _        dS )z?Register a live batch subscriber (callable(batch: list[dict])).TN)r   rK   r   r    callbacks     r!   	subscribezMonitoringEmitter.subscribev   s2    4,,,$$X...r#   c                ~    	 | j                             |           n# t          $ r Y nw xY w| j         s	d| _        d S d S )NF)r   remove
ValueErrorr   rT   s     r!   unsubscribezMonitoringEmitter.unsubscribe|   sa    	$$X.... 	 	 	D	  	"!DMMM	" 	"s    
**       @rE   floatc                     |dk    rdS t          j                    d
 fd}t          j        |dd          }|                                                     |	           dS )zCWait boundedly for queued and in-flight batches to finish dispatch.r   Nr   r   c                 b    j                                                                            d S N)r   joinset)finishedr    s   r!   _wait_for_completionz5MonitoringEmitter.flush.<locals>._wait_for_completion   s#    GLLNNNLLNNNNNr#   zhermes-monitoring-flushTr;   rD   r   r   )r   r   r?   rA   wait)r    rE   rc   waiterrb   s   `   @r!   flushzMonitoringEmitter.flush   s    a<<F?$$	 	 	 	 	 	 	 !'*
 
 

 	g&&&&&r#   Dict[str, int]c                v    | j                                         | j        | j        t	          | j                  dS )N)queued
dispatcheddroppedsubscribers)r   qsizer   r   rI   r   rB   s    r!   statszMonitoringEmitter.stats   s7    gmmoo*}t011	
 
 	
r#   c                    | j                                          | j        | j                            d           d| _        d S )Nr[   rD   F)r   ra   r   r`   r   rB   s    r!   closezMonitoringEmitter.close   s@    
<#Lc***r#   N)r   r   r   r   r$   r   r   r   rd   )r[   )rE   r\   r   r   )r   rh   )__name__
__module____qualname____doc__r"   r9   r0   r@   rL   rV   rZ   rg   ro   rq    r#   r!   r	   r	   $   s        II*. % % % % % %B B B B4
! 
! 
! 
!( ( ( ($' ' ' '   " " " "' ' ' ' '&
 
 
 
     r#   r	   Optional[MonitoringEmitter]_EMITTERr   c                     t           t           S t          5  t           t          d          a ddd           n# 1 swxY w Y   t           S )z+Return the process-wide monitoring emitter.NFr
   )ry   _EMITTER_LOCKr	   rw   r#   r!   get_emitterr|      s     	 8 8 )777H	8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
 Os   :>>r$   r   r   c                H    t                                          |            dS )z1Module-level convenience: emit via the singleton.N)r|   r9   )r$   s    r!   r9   r9      s     MMur#   emitterc                    t           5  t          4| t          ur+	 t                                           n# t          $ r Y nw xY w| addd           dS # 1 swxY w Y   dS )z Swap the singleton (tests only).N)r{   ry   rq   r5   )r~   s    r!   reset_emitter_for_testsr      s     
  G8$;$;                        s0   A4A
AA AAAA)r	   TelemetryEmitterr|   r9   r   )r   r	   rr   r_   )r~   rx   r   r   )rv   
__future__r   loggingr   r   r.   typingr   r   r   	getLoggerrs   r6   r   rJ   r	   ry   __annotations__r   r{   r|   r9   r   r   __all__rw   r#   r!   <module>r      s:    * # " " " " "        & & & & & & & & & &		8	$	$
@ @ @ @ @ @ @ @H )- , , , ,	  
 
 
 
   
	 	 	 	 	 %   r#   