diff --git a/docs/metrics-plan.md b/docs/metrics-plan.md new file mode 100644 index 0000000..08c43b0 --- /dev/null +++ b/docs/metrics-plan.md @@ -0,0 +1,355 @@ +# Plan de métricas del bot + +Este documento recoge: + +1. Inventario de las métricas **ya existentes** en el código. +2. Clasificación de cada métrica: + - **core**: queremos cuidarla y mantenerla estable. + - **nice-to-have**: útil, pero no crítica; se puede ajustar. + - **debug**: orientada a depuración / exploración. + - **dudosa**: probablemente haya que redefinirla o eliminarla. +3. Propuesta de **set “core v1”** (existentes + nuevas). +4. Notas sobre **persistencia** y derivación desde BD. +5. Próximos pasos para implementación. + +--- + +## 1. Inventario actual de métricas + +> Nota: solo se listan métricas usadas en código de producción (no tests ni docs). + +### 1.1. HTTP / Webhook / Tráfico + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|------------------------------------------|----------|-------------------|--------------------------------------------|----------------------------------------------------------------|-----------| +| `webhook_events_total_*` | counter | Webhook | `evtNorm` embebido en el nombre (`*_xxx`) | Contar eventos de webhook por tipo (messages.upsert, etc.). | core | +| `webhook_errors_total` | counter | Webhook | – | Errores procesando webhooks. | core | +| `unknown_groups_discovered_total` | counter | Webhook/grupos | – | Mensajes recibidos de grupos no conocidos en BD. | nice-to-have | +| `messages_blocked_group_total` | counter | Webhook/grupos | – | Mensajes bloqueados por venir de grupos no permitidos. | nice-to-have | + +### 1.2. Onboarding (grupos, DMs, asignaciones) + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|------------------------------------------|----------|---------------------|------------------------------------------------------------|-----------------------------------------------------------------|----------------| +| `onboarding_prompts_sent_total` | counter | Onboarding-grupos | `group_id`, `source`, `reason` | Prompts de onboarding enviados al grupo. | core (producto)| +| `onboarding_prompts_skipped_total` | counter | Onboarding-grupos | `group_id`, `source?`, `reason` | Casos donde se decide no enviar prompt al grupo. | core (producto)| +| `onboarding_assign_failures_total` | counter | Onboarding-asignac. | `group_id`, `source`, `reason` | Fallos al autoasignar tarea en onboarding. | nice-to-have | +| `onboarding_dm_skipped_total` | counter | Onboarding-DM | `reason`, `group_id` | Razones por las que NO se envía DM de onboarding. | core (producto)| +| `onboarding_dm_sent_total` | counter | Onboarding-DM | `variant`, `part`, `group_id` | DMs de onboarding efectivamente enviados. | core (producto)| +| `onboarding_recipients_capped_total` | counter | Onboarding-DM | `group_id` | Número de destinatarios que se quedaron fuera por cap. | nice-to-have | +| `onboarding_bundle_sent_total` | counter | Onboarding-DM | `variant`, `group_id` | “Bundles” de onboarding enviados. | nice-to-have | +| `onboarding_dm_sent_abs` | gauge | Onboarding-analytics| – | Valor absoluto de DMs enviados (derivado). | debug | +| `onboarding_recipients_abs` | gauge | Onboarding-analytics| – | Destinatarios totales (derivado). | debug | +| `onboarding_converted_users_abs` | gauge | Onboarding-analytics| – | Usuarios convertidos (derivado). | debug | +| `onboarding_conversion_rate` | gauge | Onboarding-analytics| – | Ratio de conversión calculado. | debug / dudosa | + +### 1.3. Reacciones / Cola de respuestas + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|--------------------------------------------------|----------|------------------|-------------------------|--------------------------------------------------------|--------------| +| `reactions_enqueued_total` | counter | Reacciones/cola | `emoji` | Reacciones encoladas para enviar. | nice-to-have | +| `reactions_sent_total` | counter | Reacciones/cola | `emoji` | Reacciones enviadas con éxito. | nice-to-have | +| `reactions_failed_total` | counter | Reacciones/cola | `emoji` | Reacciones que fallaron al enviar. | nice-to-have | +| `responses_skipped_unresolvable_recipient_total` | counter | Cola respuestas | `reason` (`non_numeric`, `too_long`, `bad_domain`…) | Respuestas descartadas por no poder resolver el JID. | debug (útil) | + +### 1.4. Recordatorios + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|----------------------------------------|----------|--------------|--------------------|----------------------------------------------------------|--------------| +| `reminders_skipped_outside_window_total` | counter | Recordatorios| – | Recordatorios omitidos por estar fuera de ventana horaria. | dudosa (parcial) | + +### 1.5. Group sync / grupos / miembros + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|--------------------------------------|----------|---------------|-----------------------------|-----------------------------------------------------------------|--------------| +| `sync_runs_total` | counter | Group sync | – | Número de ejecuciones de sync. | core (ops) | +| `sync_errors_total` | counter | Group sync | – | Errores en ejecuciones de sync. | core (ops) | +| `sync_skipped_group_total` | counter | Group sync | – | Grupos ignorados en la reconciliación (varios motivos). | nice-to-have | +| `allowed_groups_labels_filled_total` | counter | Group sync | – | Conteo de grupos donde se rellenaron labels de allowed_groups. | debug | +| `active_groups` | gauge | Group sync | – | Número de grupos activos cacheados. | core | +| `active_members` | gauge | Group sync | – | Conteo de miembros activos (BD). | core | +| `last_sync_timestamp_seconds` | gauge | Group sync | – | Marca de tiempo del último sync correcto. | core | +| `last_sync_ok` | gauge | Group sync | – | 1 si último sync OK, 0 si falló. | core | +| `last_sync_duration_ms` | gauge | Group sync | – | Duración del último sync. | core | +| `alias_coverage_ratio` | gauge | Group sync | `group_id` | Cobertura de alias de identidad en el grupo. | debug/nice | +| `allowed_groups_total_pending` | gauge | Allowed groups| – | Grupos en estado `pending`. | core | +| `allowed_groups_total_allowed` | gauge | Allowed groups| – | Grupos en estado `allowed`. | core | +| `allowed_groups_total_blocked` | gauge | Allowed groups| – | Grupos en estado `blocked`. | core | +| `group_sync_seconds_until_next` | gauge | Group sync | – | Segundos hasta el próximo sync, o -1 si inactivo. | core | + +### 1.6. Identidad / alias + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|-----------------------------------|----------|-----------|--------------------|----------------------------------------------------|----------| +| `identity_alias_upsert_errors_total` | counter| Identidad | – | Errores al hacer upsert de alias. | debug | +| `identity_alias_upserts_total` | counter| Identidad | – | Número de upserts de alias realizados. | debug | +| `identity_alias_resolved_total` | counter| Identidad | – | Alias resueltos correctamente. | debug | +| `identity_alias_unresolved_total` | counter| Identidad | – | Casos en los que no se pudo resolver alias. | debug | + +### 1.7. Administración (allow/block/list) + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|----------------------------|----------|-------------|--------------------|--------------------------------------------------------|--------------| +| `admin_actions_total_allow`| counter | Admin | – | Acciones de “allow” hechas por admins. | nice-to-have | +| `admin_actions_total_block`| counter | Admin | – | Acciones de “block” hechas por admins. | nice-to-have | +| `admin_actions_total_list` | counter | Admin | – | Invocaciones a listados de allowed_groups. | nice-to-have | + +### 1.8. Comandos + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|----------------------------|----------|------------|------------------------|----------------------------------------------------------|---------------| +| `commands_alias_used_total`| counter | Comandos | `action=info|mias|...` | Uso de alias de comandos. | nice-to-have | +| `commands_unknown_total` | counter | Comandos | – | Mensajes que no se mapean a ningún comando. | core (debug/ux)| +| `commands_blocked_total` | counter | Comandos | – | Comandos bloqueados (p.ej. grupo no permitido). | core (producto/ops) | +| `ver_dm_transition_total` | counter | Comandos | – | Veces que se hace transición a “ver por DM”. | nice-to-have | +| `web_tokens_issued_total` | counter | Web tokens | – | Número de tokens web emitidos. | nice-to-have | + +### 1.9. Mantenimiento / “evolution” (instancia WA) + +| Métrica | Tipo | Ámbito | Labels principales | Uso actual / intención | Categoría | +|-------------------------------------------|----------|--------------|----------------------------|-------------------------------------------------------------|------------| +| `evolution_instance_state_changes_total` | counter | Evolution | `instance` | Número de cambios de estado de la instancia. | core (ops) | +| `evolution_health_check_errors_total` | counter | Evolution | `instance` | Errores en health checks. | core (ops) | +| `evolution_instance_restart_attempts_total`| counter | Evolution | `instance` | Intentos de reinicio de la instancia. | core (ops) | +| `evolution_instance_restart_success_total`| counter | Evolution | `instance` | Reinicios exitosos de la instancia. | core (ops) | +| `evolution_instance_state` | gauge | Evolution | `instance`, `state` | Estados actuales de la instancia (por valor de `state`). | core (ops) | +| `evolution_instance_last_state_change_ts` | gauge | Evolution | `instance` | Timestamp del último cambio de estado. | nice-to-have | +| `evolution_instance_state_age_seconds` | gauge | Evolution | `instance` | Tiempo en segundos en el estado actual. | nice-to-have | + +--- + +## 2. Propuesta de set “core v1” (existentes) + +### 2.1. Operación / salud + +**Mantener como core:** + +- Webhook / HTTP: + - `webhook_events_total_*` + - `webhook_errors_total` +- Group sync: + - `sync_runs_total` + - `sync_errors_total` + - `active_groups` + - `active_members` + - `last_sync_timestamp_seconds` + - `last_sync_ok` + - `last_sync_duration_ms` + - `group_sync_seconds_until_next` + - `allowed_groups_total_pending` + - `allowed_groups_total_allowed` + - `allowed_groups_total_blocked` +- Evolution / instancia WA: + - `evolution_instance_state_changes_total` + - `evolution_health_check_errors_total` + - `evolution_instance_restart_attempts_total` + - `evolution_instance_restart_success_total` + - `evolution_instance_state` + +### 2.2. Experiencia de usuario / producto + +**Mantener como core:** + +- Onboarding: + - `onboarding_prompts_sent_total` + - `onboarding_prompts_skipped_total` + - `onboarding_dm_sent_total` + - `onboarding_dm_skipped_total` +- Comandos: + - `commands_unknown_total` + - `commands_blocked_total` + +--- + +## 3. Métricas existentes marcadas como “nice-to-have” o “debug” + +### 3.1. Nice-to-have (mantener pero sin contrato fuerte) + +- Webhook / grupos: + - `unknown_groups_discovered_total` + - `messages_blocked_group_total` +- Onboarding: + - `onboarding_assign_failures_total` + - `onboarding_recipients_capped_total` + - `onboarding_bundle_sent_total` +- Reacciones: + - `reactions_enqueued_total` / `reactions_sent_total` / `reactions_failed_total` +- Group sync: + - `sync_skipped_group_total` + - `alias_coverage_ratio` (si se usa en dashboards) +- Administración: + - `admin_actions_total_allow` + - `admin_actions_total_block` + - `admin_actions_total_list` +- Comandos: + - `commands_alias_used_total` + - `ver_dm_transition_total` + - `web_tokens_issued_total` +- Evolution: + - `evolution_instance_last_state_change_ts` + - `evolution_instance_state_age_seconds` + +### 3.2. Debug / dudosas (candidatas a simplificar o eliminar) + +- Onboarding analytics: + - `onboarding_dm_sent_abs` + - `onboarding_recipients_abs` + - `onboarding_converted_users_abs` + - `onboarding_conversion_rate` +- Identidad / alias: + - `identity_alias_upsert_errors_total` + - `identity_alias_upserts_total` + - `identity_alias_resolved_total` + - `identity_alias_unresolved_total` +- Cola de respuestas: + - `responses_skipped_unresolvable_recipient_total` (debug útil → mantener como tal). +- Recordatorios: + - `reminders_skipped_outside_window_total` (parcial: solo una razón de skip, sin contexto de enviados totales). + +--- + +## 4. Métricas nuevas propuestas (faltantes importantes) + +> Nota: nombres sujetos a ajuste, pero la idea es que sean lo más “Prometheus-friendly” posible. + +### 4.1. Tareas + +- **Counters (idealmente derivables de BD, o directamente desde DB en `/metrics`):** + - `tasks_created_total` + - Definición: `COUNT(*) FROM tasks`. + - `tasks_completed_total` + - Definición: `COUNT(*) FROM tasks WHERE completed = 1`. + +- **Gauges (derivables de BD):** + - `tasks_active` + - Definición: tareas no completadas (criterio exacto según modelo). + - `tasks_overdue` + - Definición: tareas no completadas con `due_date < hoy`. + - (Opcional) `tasks_active_by_group` con label `group_id` **solo si** el número de grupos es manejable y se considera útil. + +### 4.2. Mensajes y cola de respuestas + +- **Tráfico recibido (webhook):** + - `bot_messages_received_total` (counter, en memoria) + - Labels: `kind=text|reaction|system|other`. + +- **Tráfico enviado por el bot (muy importante, idealmente persistente):** + - `bot_messages_sent_total` (counter, **persistente** o derivado de BD si posible) + - Labels: `kind=reply|reminder|onboarding|error|other`. + +- **Cola de respuestas:** + - Counters: + - `response_queue_enqueued_total` (por tipo de mensaje/reacción). + - `response_queue_sent_total`. + - `response_queue_failed_total`. + - `response_queue_retried_total`. + - `response_queue_exhausted_total` (cuando se dan por fallidos tras reintentos). + - Gauges (desde BD): + - `response_queue_pending` + - `COUNT(*) FROM response_queue WHERE status='pending'`. + - `response_queue_oldest_age_seconds` + - `now - MIN(created_at)` de los pendientes. + +### 4.3. Recordatorios (visión completa) + +- Counters: + - `reminders_scheduled_total` + - Cuando se programa un recordatorio. + - `reminders_sent_total` + - Recordatorios enviados efectivamente. + - `reminders_failed_total` + - Intentos de envío de recordatorio fallidos. + - `reminders_skipped_total` + - Con labels `reason=outside_window|user_opt_out|group_not_allowed|gating|invalid_time|other`. + +- Opcionalmente ratios calculables en dashboards: + - `reminders_skipped_total / (reminders_sent_total + reminders_skipped_total)`. + +### 4.4. Uso de ICS / Web + +- ICS: + - `ics_requests_total` (counter) + - Labels: `type=personal|group|aggregate`, `status_class=2xx|4xx|5xx`. + +- HTTP genérico (si se desea): + - `http_requests_total` + - Labels: `handler=webhook|metrics|ics|web_ui|...`, `status_class=2xx|4xx|5xx`. + +### 4.5. Otras métricas posibles (según prioridad) + +- Usuarios / grupos (como gauges desde BD): + - `groups_total`, `groups_active_total`. + - `group_members_total` (activos). + - `users_total`. + - `users_active_30d` (si hay `last_seen_at`). + +--- + +## 5. Persistencia vs. métricas derivadas + +### 5.1. Derivadas desde BD (sin cambiar `Metrics`) + +Buenas candidatas: + +- `tasks_*` (`created`, `completed`, `active`, `overdue`). +- `groups_*` (`total`, `active`). +- `group_members_total`. +- `allowed_groups_total_*` (ya se hace). +- `response_queue_pending`, `response_queue_oldest_age_seconds`. + +Ventaja: son **persistentes por diseño**, no dependen de reinicios del proceso. + +### 5.2. Contadores en memoria (se reinician) + +Buenas candidatas: + +- Tráfico “reciente”: + - `bot_messages_received_total`. + - `http_requests_total`. +- Eventos de corto plazo: + - `sync_runs_total`, `sync_errors_total`. + - `evolution_*` (si además se pueden inferir de logs/BD, no es grave que se reinicien). + +Estos están bien para **tendencias recientes**, SLIs y alertas basadas en tasas. + +### 5.3. Contadores que probablemente queremos **persistir** + +Lista corta para no complicar demasiado: + +- `bot_messages_sent_total` +- `reminders_sent_total` +- (Opcional) `webhook_events_received_total` (si se agrega unificado, en lugar de solo por tipo). + +Opciones: + +1. Crear una tabla `persistent_metrics(name TEXT PRIMARY KEY, value INTEGER NOT NULL)`. +2. Implementar funciones de “incremento persistente” que actualicen BD y, opcionalmente, el estado de `Metrics`. +3. Al renderizar `/metrics`, leer estos valores persistentes y exponerlos. + +--- + +## 6. Próximos pasos sugeridos + +1. **Validar este set “core v1”**: + - Confirmar que las métricas “core existentes” listadas arriba son realmente las que quieres cuidar. + - Elegir cuáles de las nuevas propuestas son **imprescindibles** en la primera iteración (p.ej. tareas + mensajes + cola + recordatorios). + +2. **Definir contrato de nombres**: + - Cerrar nombres finales de: + - `tasks_*` + - `bot_messages_*` + - `response_queue_*` + - `reminders_*` + - `ics_requests_total` / `http_requests_total`. + +3. **Implementar por fases**: + - Fase 1: gauges derivadas de BD en `/metrics` (tareas, cola, grupos, etc.). + - Fase 2: counters en memoria (mensajes recibidos/enviados, recordatorios, cola). + - Fase 3: mecanismo de métricas persistentes y migrar los 2–3 contadores elegidos. + +4. **Limpiar / reclasificar métricas “debug/dudosas”**: + - Mantener `responses_skipped_unresolvable_recipient_total` como debug útil. + - Simplificar o eliminar gauges de onboarding `*_abs` / `conversion_rate` si no se usan. + - Revisar `reminders_skipped_outside_window_total` cuando exista el set completo de `reminders_*`. + +Este documento sirve como referencia para saber qué métricas existen, cuáles son “de contrato” y cuáles se pueden tocar con menos miedo, además de qué huecos importantes hay que cubrir en próximas iteraciones.