
     Yj87                     :   d Z ddlZddlZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
 ddlmZmZ ddd	d
dddZ ej        d          Z ej        d          Z ej        d          ZddddddZdede	e         fdZdede	e         fdZdede	e         fdZdede	e         fdZdede
e         defdZdddddded e	e         d!e	e         d"e	e         d#e	e
e                  defd$Z	 d8d&d'ddddd(d)ed*ed+ed,e	e         d-e	e         d"e	e         d.e	e         ddfd/Zd'ddddd0d1ed*ed2ed e	e         d!e	e         d"e	e         d#e	e
e                  defd3Zd1ed4edefd5Z dddddd1ed e	e         d!e	e         d"e	e         d#e	e
e                  ddfd6Z!d9d7Z"dS ):u  ``hermes logs`` — view and filter Hermes log files.

Supports tailing, following, session filtering, level filtering,
component filtering, and relative time ranges.  All log files live
under ``~/.hermes/logs/``.

Usage examples::

    hermes logs                    # last 50 lines of agent.log
    hermes logs -f                 # follow agent.log in real time
    hermes logs errors             # last 50 lines of errors.log
    hermes logs gateway -n 100    # last 100 lines of gateway.log
    hermes logs gui -f            # follow gui.log (dashboard/pty/ws)
    hermes logs desktop -f        # follow desktop.log (Electron app boot/backend)
    hermes logs --level WARNING    # only WARNING+ lines
    hermes logs --session abc123   # filter by session ID substring
    hermes logs --component tools  # only tool-related lines
    hermes logs --since 1h         # lines from the last hour
    hermes logs --since 30m -f     # follow, starting 30 min ago
    N)datetime	timedelta)Path)OptionalSequence)get_hermes_homedisplay_hermes_homez	agent.logz
errors.logzgateway.logzgui.logzdesktop.logzmcp-stderr.log)agenterrorsgatewayguidesktopmcpz(^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})z'\s(DEBUG|INFO|WARNING|ERROR|CRITICAL)\sz?\s(?:DEBUG|INFO|WARNING|ERROR|CRITICAL)(?:\s+\[.*?\])?\s+(\S+):            )DEBUGINFOWARNINGERRORCRITICAL	since_strreturnc                    |                                                                  } t          j        d|           }|sdS t	          |                    d                    }|                    d          }t          |          t          |          t          |          t          |          d	|         }t          j                    |z
  S )
zParse a relative time string like '1h', '30m', '2d' into a datetime cutoff.

    Returns None if the string can't be parsed.
    z^(\d+)\s*([smhd])$Nr   r   )seconds)minutes)hours)days)smhd)	striplowerrematchintgroupr   r   now)r   r'   valueunitdeltas        DC:\Users\server\AppData\Local\hermes\hermes-agent\hermes_cli\logs.py_parse_sincer/   ?   s    
 !!''))IH*I66E tAE;;q>>Du%%%u%%%U###E"""	 
 E <>>E!!    linec                     t                               |           }|sdS 	 t          j        |                    d          d          S # t
          $ r Y dS w xY w)zAExtract timestamp from a log line. Returns None if not parseable.Nr   z%Y-%m-%d %H:%M:%S)_TS_REr'   r   strptimer)   
ValueErrorr1   r!   s     r.   _parse_line_timestampr7   S   se    TA t -@AAA   tts   'A 
AAc                 h    t                               |           }|r|                    d          ndS )z"Extract the log level from a line.r   N)	_LEVEL_REsearchr)   r6   s     r.   _extract_levelr;   ^   s.    A$1771:::$r0   c                 h    t                               |           }|r|                    d          ndS )z(Extract the logger name from a log line.r   N)_LOGGER_NAME_REr:   r)   r6   s     r.   _extract_logger_namer>   d   s.    t$$A$1771:::$r0   prefixesc                 l    t          |           }|dS |                    t          |                    S )z@Check if a log line's logger name starts with any of *prefixes*.NF)r>   
startswithtuple)r1   r?   names      r.   _line_matches_componentrD   j   s1    %%D|u??5??+++r0   	min_levelsession_filtersincecomponent_prefixesrF   rG   rH   rI   c                   |t          |           }|||k     rdS |Kt          |           }|:t                              |d          t                              |d          k     rdS ||| vrdS |t	          | |          sdS dS )z.Check if a log line passes all active filters.NFr   T)r7   r;   _LEVEL_ORDERgetrD   )r1   rF   rG   rH   rI   tslevels          r.   _matches_filtersrO   r   s     "4((>b5jj5t$$q))L,<,<Y,J,JJJu!%%5%&t-?@@ 	54r0   r
   2   F)	num_linesfollowrN   sessionrH   	componentlog_namerQ   rR   rN   rS   rT   c          
         t                               |           }|Nt          d| dd                    t	          t                                           t          j        d           t                      dz  |z  }|                                s5t          d|            t          d           t          j        d           d}	|r8t          |          }	|	't          d	|d
           t          j        d           |r|
                                nd}
|
r0|
t          vr't          d|d           t          j        d           d}|rqddlm} |                                }||vrKd                    t	          |                    }t          d|d|            t          j        d           ||         }|
dup|dup|	dup|du}	 t          ||||
||	|          }n6# t           $ r) t          d|            t          j        d           Y nw xY wg }|
r|                    d|
            |r|                    d|            |r|                    d|            |r|                    d|            |rdd                    |           dnd}|r%t          dt%                       d| | d           n't          dt%                       d| | d| d           |D ]}t          |d           |sdS 	 t'          ||
||	|           dS # t(          $ r t          d            Y dS w xY w)!ag  Read and display log lines, optionally following in real time.

    Parameters
    ----------
    log_name
        Which log to read: ``"agent"``, ``"errors"``, ``"gateway"``, ``"gui"``.
    num_lines
        Number of recent lines to show (before follow starts).
    follow
        If True, keep watching for new lines (Ctrl+C to stop).
    level
        Minimum log level to show (e.g. ``"WARNING"``).
    session
        Session ID substring to filter on.
    since
        Relative time string (e.g. ``"1h"``, ``"30m"``).
    component
        Component name to filter by (e.g. ``"gateway"``, ``"tools"``).
    NzUnknown log: z. Available: z, r   logszLog file not found: u?   (Logs are created when Hermes runs — try 'hermes chat' first)zInvalid --since value: z$. Use format like '1h', '30m', '2d'.zInvalid --level: z/. Use DEBUG, INFO, WARNING, ERROR, or CRITICAL.r   )COMPONENT_PREFIXESzUnknown component: has_filtersrF   rG   rH   rI   zPermission denied: zlevel>=zsession=z
component=zsince=z [] z--- /logs/z (Ctrl+C to stop) ---z (last z) ---endrE   z
--- stopped ---)	LOG_FILESrL   printjoinsortedsysexitr   existsr/   upperrK   hermes_loggingrX   r%   
_read_tailPermissionErrorappendr	   _follow_logKeyboardInterrupt)rU   rQ   rR   rN   rS   rH   rT   filenamelog_pathsince_dtrF   rI   rX   component_lower	availablerZ   linesfilter_partsfilter_descr1   s                       r.   tail_logrv      sX   : }}X&&HUhUUtyy	ARAR7S7SUUVVV  6)H4H?? /X//000OPPP H &&YEYYYZZZHQKKK!&0DI Yl22Z%ZZZ[[[  A555555#//++"444		&);"<"<==IM	MM)MMNNNHQKKK/@ 	 	*$	*4	* T)	 8YK%.w!)>PR R R    .H..///
 L 31i11222 20w00111 6444555 .,U,,---5AI1tyy..1111rK b^(**^^(^K^^^____`(**``(`K``PY```aaa  d #H	'#8J	L 	L 	L 	L 	L 	L # # #!""""""#s$   G+ +0HHL' 'MMrY   pathrZ   c                    |r=t          | t          |dz  d                    }fd|D             }|| d         S t          | |          S )zRead the last *num_lines* matching lines from a log file.

    When filters are active, we read more raw lines to find enough matches.
       i  c           	      <    g | ]}t          |           |S )rE   )rO   ).0lrI   rF   rG   rH   s     r.   
<listcomp>z_read_tail.<locals>.<listcomp>  sM     
 
 
Y/=U3EG G G

 
 
r0   N)_read_last_n_linesmax)	rw   rQ   rZ   rF   rG   rH   rI   	raw_linesfiltereds	      ````  r.   ri   ri      s      3 'tSR-F-FGG	
 
 
 
 
 
 
 
 
 
 
$$!$	222r0   nc                    	 |                                  j        }|dk    rg S |dk    rJt          | ddd          5 }|                                }ddd           n# 1 swxY w Y   || d         S t          | d          5 }d	}g }|}|dk    rt	          |          |d
z   k    rt          ||          }||z  }|                    |           |                    |          }	|	                    d          }
|r"|
d         |d         z   |d<   |
dd         |z   }n|
}t          |dz  d          }|dk    rt	          |          |d
z   k    g }|D ]}|	                                s	 |
                    |                    dd          dz              F# t          $ r. |
                    |                    d          dz              Y }w xY w|| d         cddd           S # 1 swxY w Y   dS # t          $ rM t          | ddd          5 }|                                }ddd           n# 1 swxY w Y   || d         cY S w xY w)zEfficiently read the last N lines from a file.

    For files under 1MB, reads the whole file (fast, simple).
    For larger files, reads chunks from the end.
    r      rutf-8replaceencodingr   Nrbi    r      
r   i   )r   
zlatin-1)statst_sizeopen	readlineslenminseekreadsplitr$   rk   decode	Exception)rw   r   sizef	all_lines
chunk_sizers   pos	read_sizechunkchunk_linesdecodedraws                r.   r~   r~     sf   /yy{{"199I 9dC')DDD *KKMM	* * * * * * * * * * * * * * *aRSS>! $ 	 JEC''c%jjAE11
C00	y sy))#kk%00 (  +2q9E!H',u4EE'E a77
 ''c%jjAE11  G A Ayy{{ ANN3::gi:#H#H4#OPPPP  A A ANN3::i#8#84#?@@@@@AA233<;	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	 >    $gi@@@ 	&AI	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	&!~	s    G8 G8 AG8 A!!G8 $A!%G8 3G8 C'G++-FG+5GG+GG+G8 +G//G8 2G/3G8 8IH6*I6H:	:I=H:	>IIc                P   t          | ddd          5 }|                    dd           	 |                                }|rDt          |||||          r/t	          |d	
           t
          j                                         nt          j	        d           o# 1 swxY w Y   dS )z9Poll a log file for new content and print matching lines.r   r   r   r   r   r   TrE   r\   r^   g333333?N)
r   r   readlinerO   ra   rd   stdoutflushtimesleep)rw   rF   rG   rH   rI   r   r1   s          r.   rl   rl   U  s     
dC')	<	<	<  	q!		 ::<<D  #DI3A7IK K K ' $B''''J$$&&&
3		                    s   BBB"Bc            	      (   t                      dz  } |                                 s!t          dt                       d           dS t          dt                       d           d}t	          |                                           D ]t}|                                r\|j        dk    rP|                                j	        }t          j        |                                j                  }|d	k     r| d
}n|dk     r
|d	z  dd}n	|dz  dd}t          j                    |z
  }|                                dk     rd}n|                                dk     r(t          |                                dz             d}nU|                                dk     r(t          |                                dz             d}n|                    d          }t          d|j        dd|dd|            d}v|st          d           dS dS )z%Print available log files with sizes.rW   zNo logs directory at r]   NzLog files in z/logs/:
Fz.logi   Br   z.1fKBMB<   zjust nowi  zm agoiQ zh agoz%Y-%m-%dz  z<25 z>8z   Tu;     (no log files yet — run 'hermes chat' to generate logs))r   rf   ra   r	   rc   iterdiris_filesuffixr   r   r   fromtimestampst_mtimer*   total_secondsr(   strftimerC   )log_dirfoundentryr   mtimesize_strageage_strs           r.   	list_logsr   m  sD   &(G>> C&9&;&;CCCDDD	
:-//
:
:
:;;;E))**  ==?? 	u|v55::<<'D*5::<<+@AAEd{{":::##"Tk1111"k2::::,..5(C  ""R''$""$$t++ !2!2!4!4r!9::AAA""$$u,, !2!2!4!4t!;<<CCC..44AuzAAAAAAAABBBE MKLLLLLM Mr0   )r
   )r   N)#__doc__r&   rd   r   r   r   pathlibr   typingr   r   hermes_constantsr   r	   r`   compiler3   r9   r=   rK   strr/   r7   r;   r>   boolrD   rO   r(   rv   listri   r~   rl   r    r0   r.   <module>r      sH   * 
			 



  ( ( ( ( ( ( ( (       % % % % % % % % A A A A A A A A  	 		 
?	@	@ BJABB	
 "*  A!aQOO"C "HX$6 " " " "( (:    % %# % % % %%s %x} % % % %,# ,# ,4 , , , ,  $$( $26  
 } SM	
 H !#/ 
   @ l# !#l# l# l#l# l# 	l#
 C=l# c]l# C=l# }l# 
l# l# l# l#f #$( $263 3 3
33 	3
 }3 SM3 H3 !#/3 
3 3 3 3:5T 5c 5d 5 5 5 5v  $$( $26     
  }  SM	 
 H  !#/  
       0 M  M  M  M  M  Mr0   