Incidente: la rotación de agent.log nunca funcionó en el binario compilado (WinError 32)
Cuándo
Detectado y arreglado el 01-09-2026 (v1.97.2 del SaaS, Local Agent 2.26.2, PR #485, commit e5027651). El defecto llevaba activo desde la propia versión que introdujo la rotación, Agent 2.24.0 (28-08-2026, [[feature—monitoring—agente-2-24-0-task-270]]) — cuatro días en los que la rotación no funcionó ni una sola vez en el binario real, aunque los tests locales pasaban.
Síntomas visibles
En la máquina de Edu, agent.log medía 322 MB con 91 fallos de rotación en las últimas 3000 líneas. El propio RotatingFileHandler escribía el error de su fallo en el mismo fichero que no podía rotar, así que el síntoma quedaba enterrado dentro del log que crecía sin control (~6-7 MB/día). En una máquina cliente sin supervisión, ese crecimiento no tiene techo.
Causa raíz
El .exe del Local Agent se compila con PyInstaller --noconsole (ver [[concept—general—como-esta-construido-el-local-agent-que-dependenci]]), así que sys.stdout/sys.stderr son None al arrancar. setup_logging() cubría ese caso abriendo dos handles persistentes de escritura sobre el mismo agent.log que el RotatingFileHandler intentaba rotar. Windows rechaza renombrar un fichero con handles abiertos (WinError 32), así que la rotación de 2.24.0 fallaba en TODOS los intentos, siempre, en cualquier máquina cliente (el .exe siempre va sin consola). Los tests que sí pasaban corrían con Python normal, donde sys.stdout no es None y esa rama nunca se ejercitaba.
Fix aplicado
Commit e5027651 (PR #485, v1.97.2 / Agent 2.26.2):
- La salida de emergencia (tracebacks de crash, prints de terceros que no pasan por
logging) se redirige a un fichero propio,agent-stdio.log, con tope de 2 MB truncado al arrancar si lo supera — nunca vuelve a compartir handle conagent.log. - Limpieza del legado: un
agent.logpor encima de 4x el tope (20 MB) solo puede venir de estos meses sin rotar; se trunca al arrancar en vez de rotarlo (rotarlo no libera disco, solo renombra el problema aagent.log.1). La flota se limpia sola al actualizar. - 5 tests nuevos en
tests/agent/test_agent_log_rotacion.py; uno fija la causa raíz como contrato — si alguien vuelve a apuntarsys.stdoutal fichero que rota, el test lo caza.
Lecciones
- Un test de rotación en un entorno con consola (Python normal) no prueba nada sobre el binario real: la condición que dispara el bug (
sys.stdout is None) solo se da con--noconsole, y ningún test la ejercitaba. - El propio mecanismo de logging puede ocultar sus fallos: el error de rotación se escribía en el fichero que no podía rotar, así que nadie lo vio hasta medir el tamaño del fichero a mano.
- Segundo incidente distinto sobre
agent.logen 5 días (el primero, [[incident—20260827—agent-log-mudo-tras-uvicorn]], era sobredictConfigde uvicorn cerrando el handler). El área de logging del Agente acumula ya dos causas raíz independientes — candidata a revisión de conjunto en vez de fixes puntuales.
Preventivos futuros
- El test que fija el contrato (
sys.stdoutno puede apuntar al fichero rotable) cubre la regresión concreta. - Pendiente, no bloqueante: no hay verificación automática de que el binario
--noconsolecompilado se comporte igual que estos tests, que corren con Python normal — la única señal que cazó esto fue medir a mano en una máquina real.
Véase también
- [[feature—monitoring—agente-2-24-0-task-270]]
- [[incident—20260827—agent-log-mudo-tras-uvicorn]]
- [[crearack-tech—agents—dev-terminal]]
- [[concept—general—como-esta-construido-el-local-agent-que-dependenci]]
- [[crearack-tech—guides—agent-distribution]]