diff --git a/src/server.ts b/src/server.ts index ecd04a5..a48ef9b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -67,6 +67,23 @@ export class WebhookServer { if (!Metrics.enabled()) { return new Response('Metrics disabled', { status: 404 }); } + // Gauges de allowed_groups por estado (best-effort) + try { + const rows = WebhookServer.dbInstance + .prepare(`SELECT status, COUNT(*) AS c FROM allowed_groups GROUP BY status`) + .all() as any[]; + let pending = 0, allowed = 0, blocked = 0; + for (const r of rows) { + const s = String(r?.status || ''); + const c = Number(r?.c || 0); + if (s === 'pending') pending = c; + else if (s === 'allowed') allowed = c; + else if (s === 'blocked') blocked = c; + } + Metrics.set('allowed_groups_total_pending', pending); + Metrics.set('allowed_groups_total_allowed', allowed); + Metrics.set('allowed_groups_total_blocked', blocked); + } catch {} const format = (process.env.METRICS_FORMAT || 'prom').toLowerCase() === 'json' ? 'json' : 'prom'; const body = Metrics.render(format as any); return new Response(body, { diff --git a/src/services/admin.ts b/src/services/admin.ts index 69584b4..641cc67 100644 --- a/src/services/admin.ts +++ b/src/services/admin.ts @@ -2,6 +2,7 @@ import type { Database } from 'bun:sqlite'; import { db } from '../db'; import { AllowedGroups } from './allowed-groups'; import { normalizeWhatsAppId, isGroupId } from '../utils/whatsapp'; +import { Metrics } from './metrics'; type AdminContext = { sender: string; // normalized user id (digits only) @@ -82,7 +83,8 @@ export class AdminService { if (!isGroupId(ctx.groupId)) { return [{ recipient: sender, message: 'ℹ️ Este comando se debe usar dentro de un grupo.' }]; } - AllowedGroups.setStatus(ctx.groupId, 'allowed'); + const changed = AllowedGroups.setStatus(ctx.groupId, 'allowed'); + try { if (changed) Metrics.inc('admin_actions_total_allow'); } catch {} return [{ recipient: sender, message: `✅ Grupo habilitado: ${ctx.groupId}` }]; } @@ -91,7 +93,8 @@ export class AdminService { if (!isGroupId(ctx.groupId)) { return [{ recipient: sender, message: 'ℹ️ Este comando se debe usar dentro de un grupo.' }]; } - AllowedGroups.setStatus(ctx.groupId, 'blocked'); + const changed = AllowedGroups.setStatus(ctx.groupId, 'blocked'); + try { if (changed) Metrics.inc('admin_actions_total_block'); } catch {} return [{ recipient: sender, message: `✅ Grupo deshabilitado: ${ctx.groupId}` }]; } @@ -101,7 +104,8 @@ export class AdminService { if (!isGroupId(arg)) { return [{ recipient: sender, message: '⚠️ Debes indicar un group_id válido terminado en @g.us' }]; } - AllowedGroups.setStatus(arg, 'allowed'); + const changed = AllowedGroups.setStatus(arg, 'allowed'); + try { if (changed) Metrics.inc('admin_actions_total_allow'); } catch {} return [{ recipient: sender, message: `✅ Grupo habilitado: ${arg}` }]; } @@ -111,7 +115,8 @@ export class AdminService { if (!isGroupId(arg)) { return [{ recipient: sender, message: '⚠️ Debes indicar un group_id válido terminado en @g.us' }]; } - AllowedGroups.setStatus(arg, 'blocked'); + const changed = AllowedGroups.setStatus(arg, 'blocked'); + try { if (changed) Metrics.inc('admin_actions_total_block'); } catch {} return [{ recipient: sender, message: `✅ Grupo bloqueado: ${arg}` }]; } diff --git a/src/services/command.ts b/src/services/command.ts index eb3f17f..9387877 100644 --- a/src/services/command.ts +++ b/src/services/command.ts @@ -8,6 +8,7 @@ import { ICONS } from '../utils/icons'; import { padTaskId, codeId, formatDDMM, bold, italic } from '../utils/formatting'; import { IdentityService } from './identity'; import { AllowedGroups } from './allowed-groups'; +import { Metrics } from './metrics'; type CommandContext = { sender: string; // normalized user id (digits only), but accept raw too @@ -1068,6 +1069,7 @@ export class CommandService { if (mode === 'enforce') { try { if (!AllowedGroups.isAllowed(context.groupId)) { + try { Metrics.inc('commands_blocked_total'); } catch {} return []; } } catch { diff --git a/src/services/group-sync.ts b/src/services/group-sync.ts index bdc3748..55ae482 100644 --- a/src/services/group-sync.ts +++ b/src/services/group-sync.ts @@ -620,6 +620,7 @@ export class GroupSyncService { try { if (!AllowedGroups.isAllowed(groupId)) { // Saltar grupos no permitidos en modo enforce + try { Metrics.inc('sync_skipped_group_total'); } catch {} continue; } } catch { @@ -821,6 +822,7 @@ export class GroupSyncService { try { (AllowedGroups as any).dbInstance = this.dbInstance; if (!AllowedGroups.isAllowed(groupId)) { + try { Metrics.inc('sync_skipped_group_total'); } catch {} return { added: 0, updated: 0, deactivated: 0 }; } } catch {