o
    �ƒ†j™  ã                   @   s�   d 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Zddl	m
Z
 daG dd„ dejƒZd	ed
efdd„Zdd„ Zdedejfdd„ZdS )a;  
logger_setup.py

Central logging configuration. Every module calls get_logger(__name__)
to get a consistently formatted logger that writes to both console and
a log file under logs/.

[FEATURE 2026-08-20] Log files are now per trading day instead of a
single ever-growing sip_bot.log that only rotated once it hit a size
cap. Each day gets its own file named logs/sip_bot_YYYY-MM-DD.log --
the date is part of the filename from the very first message written
that day, not something bolted on after the fact via a rotated-file
suffix. A fresh file is opened automatically the moment logging
crosses into a new day, even if the process happens to keep running
across the boundary (this bot normally runs one session per trading
day and exits at EOD liquidation, but the day-check-on-emit makes this
correct too for any longer-running or overnight dry-run use).

The day boundary is anchored to market_time's America/New_York clock
(the same timezone every schedule check in this project already uses),
not naive server-local time -- on a UTC-default droplet, "server
midnight" and "trading-day midnight" are different moments, and using
the wrong one could split a single session's log across two files.

Old daily files beyond logging.retention_days are pruned on startup,
so disk usage stays bounded without needing size-based rotation.
é    N)Údate)ÚPath)Ú
get_configFc                       sj   e Zd ZdZddededef‡ fdd„Zded	efd
d„Zdd„ Z	‡ fdd„Z
dd„ Z‡ fdd„Z‡  ZS )Ú_DailyFileHandlera¢  
    Writes to logs/{prefix}_{YYYY-MM-DD}.log (America/New_York date),
    opening a new file the first time a record is emitted on a new
    trading day.

    Deliberately simpler than logging.handlers.TimedRotatingFileHandler:
    that class only embeds the date into ROTATED (past) filenames by
    default -- the currently-active file keeps the plain base name until
    it's rotated away. That doesn't match "today's log file is already
    named with today's date," and making TimedRotatingFileHandler do
    that requires overriding both its rollover timing and its active
    filename, which ends up more convoluted than just checking the date
    on each emit.
    úutf-8Úlog_dirÚprefixÚencodingc                    s,   t ƒ  ¡  || _|| _|| _d | _d | _d S ©N)ÚsuperÚ__init__Ú_log_dirÚ_prefixÚ	_encodingÚ_current_dateÚ_file_handler)Úselfr   r   r	   ©Ú	__class__© úH/var/www/screener/trade/premarket_backup_2026-09-08_2010/logger_setup.pyr   9   s   

z_DailyFileHandler.__init__ÚdayÚreturnc                 C   s   | j | j› d| ¡ › d� S )NÚ_ú.log)r   r   Ú	isoformat)r   r   r   r   r   Ú	_path_forA   s   z_DailyFileHandler._path_forc                 C   sj   t  ¡  ¡ }| jd ur| j|krd S | jd ur| j ¡  || _tj|  |¡d| j	d�| _| j 
| j¡ d S )NÚa)Úmoder	   )Úmarket_timeÚnow_etr   r   r   ÚcloseÚloggingÚFileHandlerr   r   ÚsetFormatterÚ	formatter)r   Útodayr   r   r   Ú_ensure_current_fileD   s   

ÿz&_DailyFileHandler._ensure_current_filec                    s*   t ƒ  |¡ | jd ur| j |¡ d S d S r
   )r   r$   r   )r   Úfmtr   r   r   r$   P   s   
ÿz_DailyFileHandler.setFormatterc                 C   s:   z|   ¡  | j |¡ W d S  ty   |  |¡ Y d S w r
   )r'   r   ÚemitÚ	ExceptionÚhandleError)r   Úrecordr   r   r   r)   U   s   ÿz_DailyFileHandler.emitc                    s"   | j d ur
| j  ¡  tƒ  ¡  d S r
   )r   r!   r   )r   r   r   r   r!   \   s   

z_DailyFileHandler.close)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ústrr   r   r   r'   r$   r)   r!   Ú__classcell__r   r   r   r   r   )   s    r   r   r   c              	   C   s¸   |r|dkrdS t  ¡  ¡  ¡ | }t t| |› d� ƒ¡D ];}tj |¡t	|ƒd t	dƒ … }zt 
|¡}W n	 tyA   Y qw | ¡ |k rYzt |¡ W q tyX   Y qw qdS )zËDeletes dated log files older than retention_days. Best-effort --
    a file that can't be parsed as one of ours, or can't be removed, is
    silently left alone rather than raising during logging setup.r   Nz_*.logé   r   )r   r    r   Ú	toordinalÚglobr1   ÚosÚpathÚbasenameÚlenÚfromisoformatÚ
ValueErrorÚremoveÚOSError)r   r   Úretention_daysÚcutoff_ordinalr7   ÚstemÚ	file_dater   r   r   Ú_prune_old_logsb   s$   "ÿÿýúrB   c            	      C   sæ   t rd S tƒ } |  di ¡}ttƒ ¡ j| dd¡ }|jddd� tt	| dd¡ 
¡ t	jƒ}| dd	¡}t	 d	¡}| |¡ d
|_t	jddd�}t	 ¡ }| |¡ | |¡ t||ƒ}| |¡ | |¡ t||| dd¡ƒ da d S )Nr"   r   ÚlogsT)ÚparentsÚexist_okÚlevelÚINFOÚfilename_prefixÚsip_botFz1%(asctime)s [%(levelname)s] %(name)s: %(message)sz%Y-%m-%d %H:%M:%S)Údatefmtr>   é   )Ú_CONFIGUREDr   Úgetr   Ú__file__ÚresolveÚparentÚmkdirÚgetattrr"   ÚupperrG   Ú	getLoggerÚsetLevelÚ	propagateÚ	FormatterÚStreamHandlerr$   Ú
addHandlerr   rB   )	ÚcfgÚlog_cfgr   rF   r   Úrootr(   ÚconsoleÚfile_handlerr   r   r   Ú_configure_rootv   s.   

þ




r_   Únamer   c                 C   s   t ƒ  t d| › �¡S )Nzsip_bot.)r_   r"   rT   )r`   r   r   r   Ú
get_logger˜   s   ra   )r0   r5   r"   r6   Údatetimer   Úpathlibr   r   Úconfig_loaderr   rL   ÚHandlerr   r1   rB   r_   ÚLoggerra   r   r   r   r   Ú<module>   s    9"