ADR-003: Estrategia de logs y observabilidad
Fecha: 2026-06-26
Estado: Aprobado
Responsable: Orchestrator
Contexto
Venuo tiene eventos críticos que requieren trazabilidad:
- Requests con tenant incorrecto o sin tenant — posible intento de acceso entre tenants.
- Fallos en sincronización de ventas offline — pérdida de datos potencial.
- Errores en cierre de caja — operación crítica de negocio.
- Fallos en importación masiva — el usuario está esperando resultado.
- Tareas Celery fallidas con retry agotado — pérdida de datos potencial.
403por feature flag bloqueado — tenant intentando acceder fuera de su plan.
Sin logs estructurados en producción no es posible diagnosticar incidentes ni auditar operaciones críticas.
Decisión
Estrategia en dos niveles según el momento del proyecto:
Nivel 1 — MVP (Sprint 0 en adelante)
- Logging estructurado en JSON configurado en
config/settings/base.pyvia el móduloLOGGINGde Django. Salida a stdout (capturado por Docker) y a archivo con rotación diaria en/app/logs/. - Sentry para captura de errores y excepciones con contexto completo (tenant activo, usuario, endpoint, stack trace). SDK integrado en Django y Celery. Plan gratuito suficiente para MVP.
Nivel 2 — Producción con clientes reales
- Loki + Grafana (self-hosted en docker-compose) para agregación, búsqueda histórica y dashboards. Se activa cuando el volumen de logs justifique búsquedas históricas. No requiere cambios en el código — solo agregar contenedores y configurar Promtail como agente.
Alternativas consideradas
| Alternativa | Ventajas | Desventajas |
|---|---|---|
| Solo stdout + grep | Cero configuración | Inviable en producción con múltiples contenedores |
| Loki + Grafana desde Sprint 0 | Stack completo desde el inicio | Tres contenedores extra innecesarios en MVP — recursos desperdiciados |
| Sentry + Papertrail (elegida parcialmente) | Sin infraestructura extra, plan gratuito generoso | Logs salen del servidor — consideración de privacidad |
| ELK Stack (Elasticsearch + Logstash + Kibana) | Muy potente | Pesado, costoso en recursos, excesivo para MVP |
Formato de log estructurado
Todos los logs del sistema siguen este formato JSON:
{
"level": "ERROR",
"timestamp": "2026-06-26T02:15:33Z",
"tenant": "tenant_empresa_1",
"user_id": 42,
"endpoint": "/api/caja/cerrar/",
"message": "Cierre de caja fallido — caja ya cerrada",
"extra": {}
}
Los campos tenant y user_id se inyectan automáticamente via middleware de logging en core_api.
Eventos críticos con nivel mínimo requerido
| Evento | Nivel | Destino |
|---|---|---|
| Request sin tenant válido | WARNING |
stdout + Sentry |
| Fallo en sync de venta offline | ERROR |
stdout + Sentry |
| Fallo en cierre de caja | ERROR |
stdout + Sentry |
| Fallo en importación masiva | ERROR |
stdout + Sentry |
| Tarea Celery con retry agotado | CRITICAL |
stdout + Sentry |
403 por feature flag |
INFO |
stdout |
| Login / logout | INFO |
stdout |
| Apertura / cierre de caja exitoso | INFO |
stdout |
Rotación de archivos de log
| Archivo | Retención | Criterio |
|---|---|---|
django.log |
7 días | Rotación diaria — TimedRotatingFileHandler |
celery.log |
7 días | Rotación diaria |
nginx/access.log |
7 días | Rotación via logrotate en el contenedor Nginx |
La carpeta /app/logs/ se monta como volumen en el host para persistir logs entre reinicios del contenedor.
Consecuencias
Positivas
- Sentry captura excepciones con contexto de tenant y usuario sin código adicional en cada endpoint.
- El logging estructurado en JSON es compatible con cualquier agregador futuro (Loki, ELK, Datadog).
- La migración a Loki + Grafana en producción no requiere cambios de código — solo configuración de infraestructura.
Negativas / trade-offs
- Sentry recibe datos de errores incluyendo contexto de tenants — revisar política de privacidad antes del lanzamiento. Configurar
before_sendpara filtrar datos sensibles si es necesario. - Los archivos de log en disco crecen — la rotación de 7 días los mantiene acotados.
Impacto en el sistema
- Backend: configurar módulo
LOGGINGenconfig/settings/base.py. Agregar middleware de logging encore_apique inyectetenantyuser_iden cada log. Integrar SDK de Sentry enconfig/settings/base.py. - Celery: configurar Sentry SDK para workers — captura excepciones de tareas automáticamente.
- DevOps: volumen
/app/logs/endocker-compose.yml. AgregarSENTRY_DSNa.env.example. Documentar cómo agregar Loki + Grafana cuando corresponda. - Seguridad: configurar
before_senden Sentry para filtrar campos sensibles (contraseñas, tokens, montos de caja) antes de enviar a los servidores de Sentry.
Documentos actualizados
docs/adr/ADR_INDEX.mddocs/STACK.mddocs/ARCHITECTURE.mdagents/DEVOPS_AGENT.md
Revisión futura
Activar Loki + Grafana cuando haya más de 3 tenants activos en producción o cuando el diagnóstico de incidentes requiera búsquedas históricas que grep no resuelva eficientemente.