Skip to content

Monitoring et observabilite

Health check HTTP

Le bot expose un serveur HTTP de health check sur le port configure (HEALTH_PORT, defaut 3000).

Endpoint

GET /health (ou GET /)

Reponse en cas de succes (HTTP 200)

json
{
  "status": "ok",
  "uptime": 3600,
  "memory_mb": 85,
  "timestamp": "2026-04-03T12:00:00.000Z"
}
  • uptime : secondes depuis le demarrage du processus
  • memory_mb : heap utilise en megaoctets

Reponse en cas d'erreur (HTTP 503)

json
{
  "status": "error",
  "message": "Database unreachable"
}

Le health check execute un SELECT 1 sur PostgreSQL. Si la requete echoue, HTTP 503 est renvoye.

Salon de logs Discord

Toutes les erreurs et evenements importants sont notifies dans le salon Discord configure via DISCORD_LOG_CHANNEL_ID.

La fonction notifyAdminChannel(message, level) envoie un message formate :

NiveauIconeUtilisation
info🟢Démarrage, shutdown, actions admin
warn🟡Erreurs non critiques, DM échoués
error🔴Erreurs de commandes, crons, handlers

Format : <icone> <timestamp ISO> <message>

La fonction notifyModerationChannel(guildId, message) envoie dans le salon de moderation (moderationLogChannelId) si configure, sinon dans le salon admin general.

pm2

Le bot est gere en production par pm2 avec la configuration ecosystem.config.cjs :

javascript
{
  name: 'igb-bot',
  script: 'dist/app/bootstrap.js',
  node_args: '--enable-source-maps',
  autorestart: true,
  max_restarts: 10,
  min_uptime: '10s',
  restart_delay: 5000,
  max_memory_restart: '512M'
}

Commandes utiles :

  • pm2 logs igb-bot : afficher les logs en temps reel
  • pm2 monit : tableau de bord systeme
  • pm2 restart igb-bot : redemarrage manuel

Les logs sont ecrits dans logs/pm2-error.log et logs/pm2-out.log avec merge et horodatage.

SystemLog (base de donnees)

Table SystemLog pour le stockage persistant des evenements systeme :

ChampTypeDescription
levelEnumDEBUG, INFO, WARN, ERROR
sourceStringModule source (ex: valorant-api, birthday-job)
messageStringDescription de l'evenement
detailsJson?Donnees supplementaires
createdAtDateTimeHorodatage

Index : @@index([level, createdAt]) et @@index([source, createdAt]).

Les logs systeme de plus de 30 jours sont purges automatiquement par le cron cache-purge (quotidien a 3h00).

AuditLog (base de donnees)

Table AuditLog pour le suivi des actions utilisateur :

ChampTypeDescription
guildIdStringID du serveur
userIdString?ID du profil utilisateur (relation)
actionStringType d'action (ex: SETUP, ADMIN_GIVE_XP)
detailsJson?Parametres de l'action
createdAtDateTimeHorodatage

Index : @@index([guildId, action, createdAt]).

Graceful shutdown

Le bot gere proprement les signaux d'arret (SIGTERM, SIGINT) :

  1. Sauvegarde des sessions vocales actives : parcourt tous les membres en vocal et cloture leurs sessions (calcul de l'XP vocal).
  2. Destruction du client Discord : deconnexion propre du gateway.
  3. Deconnexion de Prisma : fermeture de la connexion PostgreSQL.
  4. process.exit(0).

Si la sauvegarde des sessions vocales echoue, un warning est logue mais le shutdown continue.

Gestion des erreurs globales

Deux handlers globaux attrapent les erreurs non gerees :

uncaughtException

typescript
process.on('uncaughtException', async (err) => {
  log.fatal({ err }, 'Uncaught exception');
  await notifyAdminChannel('Uncaught exception: ...', 'error');
  process.exit(1);
});

Envoie une notification, puis arrete le processus (pm2 le relancera).

unhandledRejection

typescript
process.on('unhandledRejection', async (reason) => {
  log.error({ reason }, 'Unhandled promise rejection');
  await notifyAdminChannel('Unhandled rejection: ...', 'error');
});

Envoie une notification mais ne tue pas le processus (les rejections non gerees ne sont pas forcement fatales).