ADR-0004 · Los logs del backend van a GlitchTip, no a un stack de logs propio¶
- Estado: aceptado
- Decisores: equipo OMS (iniciativa de observabilidad)
- Fecha de la decisión: agosto 2026
- Relacionado: ADR-0003 (no lo reemplaza: lo complementa)
Contexto y problema¶
Con ADR-0003 un error de producción ya se rastrea end-to-end, pero el evento
llegaba "seco": los logger.log/warn/error del backend —incluidos los del
sap-client, que registran cada llamada al Service Layer con su duración y su
body— morían en la consola del contenedor, sin búsqueda ni retención. Para
entender qué venía pasando antes de un error había que reproducirlo.
El plan original (fase 4 de analisis/observabilidad-errores/) era montar
Loki + Grafana con nestjs-pino: dos servicios nuevos en el compose, un
shipper de logs y un dashboard que mantener.
Al verificar la instancia se encontró que GlitchTip 6.1.5 ya trae la feature
logs habilitada (enabledFeatures: ["logs","uptime","mcp"]): acepta logs
estructurados por el mismo DSN, con retención de 90 días (7 en hot storage
PostgreSQL, luego cold).
Opciones consideradas¶
- Logs nativos de GlitchTip (
enableLogs) — elegida - Loki + Grafana +
nestjs-pino(plan original) - Solo breadcrumbs, sin log persistente
Decisión¶
Un único GlitchtipLogger (registrado en NestFactory.create) reemplaza al
logger de Nest y, sin tocar los ~200 new Logger(X) existentes, hace tres
cosas con cada log/warn/error:
- Lo imprime por consola igual que antes.
- Lo agrega como breadcrumb, que viaja adjunto al evento si el request termina en error (responde "¿qué pasó antes de este error?").
- Lo envía como log estructurado a la sección Logs, con atributos
request_idycontext(responde "¿qué pasó en el request abc-123?", haya o no error).
Dos restricciones descubiertas contra la instancia real y que condicionan la implementación:
- La búsqueda de logs de GlitchTip 6.1 es full-text sobre el cuerpo del
mensaje: no filtra por atributos. Por eso el
request_idse antepone también al texto ([rid:…]), no alcanza con mandarlo como atributo. Si alguien quita ese prefijo, se rompe la búsqueda por request. - Los contextos de arranque del framework (
RouterExplorer,RoutesResolver,InstanceLoader) generan 200+ líneas por reinicio sin valor diagnóstico y consumían slots de los 50 breadcrumbs: se excluyen de GlitchTip.
El volumen se gobierna por entorno, sin redeploy: GLITCHTIP_LOGS_ENABLED
(corta el envío; los breadcrumbs siguen) y GLITCHTIP_LOGS_MIN_LEVEL
(log|warn|error).
Un log nunca genera un issue por sí solo. Para las degradaciones
silenciosas (catch que continúa con un fallback) existe captureWarning(flujo,
mensaje), explícito y de lista corta.
Consecuencias¶
Positivas¶
- Se cancela la fase 4: cero infraestructura nueva — ni Loki, ni Grafana, ni shipper, ni dos servicios más que mantener y monitorear.
- Los logs quedan correlacionados con los errores en la misma herramienta: del issue al request completo sin cambiar de pestaña.
- Volumen medido en producción: ~43.000 logs/día ≈ 30 MB/día ≈ 2,7 GB con la retención de 90 días. Asumible.
Negativas / deuda asumida¶
- Se resignan los dashboards de Grafana (tasa de errores por endpoint, p95 de duración de llamadas SAP). Si esa necesidad aparece, se replantea con un ADR nuevo.
- La búsqueda es full-text: no hay filtros por atributo ni agregaciones.
- Los logs quedan atados a la disponibilidad y al disco de la instancia de GlitchTip; conviene vigilar el crecimiento de su PostgreSQL.