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)
{
"status": "ok",
"uptime": 3600,
"memory_mb": 85,
"timestamp": "2026-04-03T12:00:00.000Z"
}uptime: secondes depuis le demarrage du processusmemory_mb: heap utilise en megaoctets
Reponse en cas d'erreur (HTTP 503)
{
"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 :
| Niveau | Icone | Utilisation |
|---|---|---|
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 :
{
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 reelpm2 monit: tableau de bord systemepm2 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 :
| Champ | Type | Description |
|---|---|---|
level | Enum | DEBUG, INFO, WARN, ERROR |
source | String | Module source (ex: valorant-api, birthday-job) |
message | String | Description de l'evenement |
details | Json? | Donnees supplementaires |
createdAt | DateTime | Horodatage |
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 :
| Champ | Type | Description |
|---|---|---|
guildId | String | ID du serveur |
userId | String? | ID du profil utilisateur (relation) |
action | String | Type d'action (ex: SETUP, ADMIN_GIVE_XP) |
details | Json? | Parametres de l'action |
createdAt | DateTime | Horodatage |
Index : @@index([guildId, action, createdAt]).
Graceful shutdown
Le bot gere proprement les signaux d'arret (SIGTERM, SIGINT) :
- Sauvegarde des sessions vocales actives : parcourt tous les membres en vocal et cloture leurs sessions (calcul de l'XP vocal).
- Destruction du client Discord : deconnexion propre du gateway.
- Deconnexion de Prisma : fermeture de la connexion PostgreSQL.
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
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
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).
