Tecnología · GUÍA PRÁCTICA
¿Python registra cada mensaje dos veces? Audita handlers y propagación
Marca un record, sigue cada handler hasta root y separa configuración repetida, defaults del framework y captura multiproceso antes de quitar un solo borde.

Una línea duplicada aún no es diagnóstico. Un LogRecord puede llegar al handler hijo y al ancestro; una ruta puede añadir handlers al mismo logger; el framework puede poseer otro stream; o procesos y collectors distintos pueden generar eventos parecidos.
La reparación segura etiqueta un registro de prueba, guarda PID, logger e identidad del handler y dibuja la ruta a cada sink. Cambia un solo límite de propiedad y repite el comando original.
Distingue evento de línea duplicada
Emite un token único con PID, logger, nivel y timestamp preciso. Captura consola, archivo y collector por separado. Texto igual puede ser eventos distintos y formatos distintos pueden ser el mismo record.
Repite mediante comando, reloader, launcher o service unit real; python app.py no prueba rutas de uvicorn, gunicorn, cron o contenedor.
Dibuja el grafo logger-handler
Registra name, disabled, effective level, propagate y cada direct handler con object id, clase, nivel, stream/file y formatter; luego recorre parents hasta root.
Si child y ancestor tienen el mismo handler o sink equivalente con propagation, hay dos rutas. Conserva un dueño o detén la propagación en un límite deliberado.
Separa setup repetido de propagación
Compara handler count antes del import, después del startup, tras un request y tras reload. Grafo estable con child/root indica propagation; count creciente indica configuración no idempotente.
Mueve el setup a una sola ruta o reutiliza un handler conocido. No deduzcas duplicación solo por clase.
Respeta dueños de framework y proceso
Inspecciona loggers del framework antes de basicConfig. Uvicorn separa parent, error y access; compara el grafo vivo con documentación actual.
Incluye PID/process name. Workers deben usar QueueHandler hacia un listener o collector; revisa también si stdout y stderr se capturan dos veces.
Quita un borde y valida
Elige un dueño por sink: root, framework branch, queue listener o collector. Quita solo el handler, setup, propagation edge o collector route probado.
Repite startup, request, warning, framework error y access event. Exige un probe por sink, count estable tras reload y conservación de streams requeridos.
