fix(logging): rotație echo-core.log + oprire scriere dublă

Loggerul `echo-core.invoke` avea handler propriu pe echo-core.log ȘI
propagare la root handler pe același fișier — fiecare linie scrisă de
două ori. La fel `echo-core.security`, scris și în security.log și în
echo-core.log. Împreună, 1.2GB de log.

- handler propriu pentru invoke: eliminat (propagarea la root ajunge)
- security_logger.propagate = False
- FileHandler → RotatingFileHandler (50MB × 5 backups)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiJGsZVSEGjRHZEJiXaxCC
This commit is contained in:
2026-09-02 12:05:18 +00:00
parent 2ba238bb01
commit d778d097d8

View File

@@ -5,6 +5,7 @@ import logging
import os import os
import signal import signal
import sys import sys
from logging.handlers import RotatingFileHandler
from pathlib import Path from pathlib import Path
# Ensure project root is on sys.path so `src.*` imports work # Ensure project root is on sys.path so `src.*` imports work
@@ -39,26 +40,36 @@ def _stop_steering_registry(logger: logging.Logger) -> None:
def setup_logging(): def setup_logging():
LOG_DIR.mkdir(parents=True, exist_ok=True) LOG_DIR.mkdir(parents=True, exist_ok=True)
fmt = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" fmt = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
# ponytail: RotatingFileHandler caps echo-core.log at 50MB x5 backups —
# stdlib, no logrotate/cron dependency. Raise maxBytes if 50MB rotates
# too often once volume is observed post-fix.
root_file_handler = RotatingFileHandler(
LOG_DIR / "echo-core.log", maxBytes=50 * 1024 * 1024, backupCount=5,
)
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format=fmt, format=fmt,
handlers=[ handlers=[
logging.FileHandler(LOG_DIR / "echo-core.log"), root_file_handler,
logging.StreamHandler(sys.stderr), logging.StreamHandler(sys.stderr),
], ],
) )
# Security log — separate file for unauthorized access attempts # Security log — separate file for unauthorized access attempts.
# propagate=False: without it, every security event was ALSO written to
# echo-core.log via the root handler (double write) — one of the two
# causes of the 1.2GB log file found 2026-09-02.
security_handler = logging.FileHandler(LOG_DIR / "security.log") security_handler = logging.FileHandler(LOG_DIR / "security.log")
security_handler.setFormatter(logging.Formatter(fmt)) security_handler.setFormatter(logging.Formatter(fmt))
security_logger = logging.getLogger("echo-core.security") security_logger = logging.getLogger("echo-core.security")
security_logger.addHandler(security_handler) security_logger.addHandler(security_handler)
security_logger.propagate = False
# Invocation log — all Claude CLI calls # Invocation log — all Claude CLI calls. Had its OWN FileHandler on
invoke_handler = logging.FileHandler(LOG_DIR / "echo-core.log") # echo-core.log *plus* propagation to the root handler on the same
invoke_handler.setFormatter(logging.Formatter(fmt)) # file — every invoke line was written twice, the main driver of the
invoke_logger = logging.getLogger("echo-core.invoke") # 1.2GB log file found 2026-09-02. No separate handler needed: default
invoke_logger.addHandler(invoke_handler) # propagation already routes it through root_file_handler above.
def main(): def main():