FEAT: Remontée des logs agents — buffer + endpoint POST /api/agents/{id}/logs #50

Closed
opened 2026-08-11 17:17:27 +02:00 by nonobis · 2 comments
Owner

Contexte

Les agents Heimdall (FFmpeg/YOLO/RTSP) loguent aujourd'hui uniquement vers stdout/Docker (ILogger .NET standard) et vers Sentry/GlitchTip si DSN configuré. Aucun log n'est visible depuis l'interface d'admin centrale : quand un agent crashe, se reconnecte en boucle ou échoue une détection, l'admin ne voit rien sans SSH.

Référence spec

Pas de section dédiée dans docs/MASTER_SPECIFICATION.md. Complète le pattern d'observabilité existant (AuditLog P0, §1.3) et la règle P1 « Secrets dans logs — sanitized : password, token, secret, snapshotUrl masqués » (ligne 510). S'inscrit dans l'étape 6 (ops/observabilité), comme les tickets #13 (health checks) et #14 (métriques).

Décisions validées (08/2026)

  • Niveau de capture = paramètre central configurable (agent.log.level, ex. Information/Warning/Error) avec override possible par agent — s'appuie sur le mécanisme AgentScopedSetting existant (migration AddAgentScopedSetting) + ConfigReceiverService (settings poussés à l'agent, pattern heartbeat.interval.seconds)
  • Rétention : 7 jours (ticket #53) — OK

État actuel

  • src/Heimdall.Agent/Program.cs : logging Microsoft.Extensions.Logging par défaut, pas de Serilog, pas de buffer
  • AgentRegistrationService : heartbeat POST /api/agents/{id}/heartbeat (API Key) toutes les 30 s avec métriques — pas de logs dans le payload
  • Pas de mécanisme de collecte/transmission de logs côté agent
  • AgentScopedSetting : table/settings par agent déjà en place (migration AddAgentScopedSetting)

À faire

  1. LogBufferService (singleton) : ring buffer borné en mémoire (taille configurable, ex. 500 entrées), thread-safe ; niveau de capture effectif = override agent si défini (AgentScopedSetting), sinon niveau global (agent.log.level)
  2. Provider/custom logger ILoggerProvider branché sur le pipeline de logging de l'agent pour capturer les entrées (timestamp, level, message, exception, composant) sans bloquer le thread appelant
  3. Endpoint dédié POST /api/agents/{id}/logs (API Key) envoyant le batch : { entries: [{ timestampUtc, level, message, exception?, source? }] } — ne pas alourdir le heartbeat (découplage volume/observabilité)
  4. Envoi périodique (toutes les N secondes ou attaché au tick heartbeat) avec queue bornée DropWrite (pas DropOldest — règle agent existante) et retry/backoff si échec ; les logs restent non-bloquants (jamais d'await bloquant dans le chemin de logging)
  5. Sanitization des secrets avant envoi (masquer password/token/secret/API key/snapshotUrl) — spec P1
  6. Si aucun log depuis X, ne rien envoyer (zéro payload = zéro bruit)

Critères d'acceptation

  • Un log émis dans l'agent (Info/Warn/Error) apparaît dans le buffer puis est transmis au central en batch
  • Le niveau de capture suit le paramètre global, et l'override par agent (AgentScopedSetting) le remplace quand défini
  • L'échec d'envoi ne fait pas perdre le buffer (retry au tick suivant, pas de crash)
  • Les messages contenant password=/token=/secret= sont masqués avant transmission
  • L'agent tourne normalement quand le central est injoignable (logs bufferisés puis vidés, sans blocage)
  • Tests unitaires agent (buffer borné, drop-write, sanitization, retry) — tests/Heimdall.Agent.Tests

Fichiers concernés

  • src/Heimdall.Agent/Services/LogBufferService.cs (nouveau)
  • src/Heimdall.Agent/Logging/AgentLoggingProvider.cs (nouveau)
  • src/Heimdall.Agent/Program.cs (enregistrement provider)
  • src/Heimdall.Agent/AgentOptions.cs + appsettings.json (niveau, taille buffer, intervalle)
  • src/Heimdall.Agent/Services/AgentRegistrationService.cs (tick d'envoi)
  • Settings : AgentScopedSetting (override par agent) + SettingsController (paramètre global)
## Contexte Les agents Heimdall (FFmpeg/YOLO/RTSP) loguent aujourd'hui uniquement vers stdout/Docker (ILogger .NET standard) et vers Sentry/GlitchTip si DSN configuré. Aucun log n'est visible depuis l'interface d'admin centrale : quand un agent crashe, se reconnecte en boucle ou échoue une détection, l'admin ne voit rien sans SSH. ## Référence spec Pas de section dédiée dans `docs/MASTER_SPECIFICATION.md`. Complète le pattern d'observabilité existant (AuditLog P0, §1.3) et la règle P1 « Secrets dans logs — sanitized : password, token, secret, snapshotUrl masqués » (ligne 510). S'inscrit dans l'étape 6 (ops/observabilité), comme les tickets #13 (health checks) et #14 (métriques). ## Décisions validées (08/2026) - **Niveau de capture = paramètre central configurable** (`agent.log.level`, ex. Information/Warning/Error) avec **override possible par agent** — s'appuie sur le mécanisme `AgentScopedSetting` existant (migration `AddAgentScopedSetting`) + `ConfigReceiverService` (settings poussés à l'agent, pattern `heartbeat.interval.seconds`) - Rétention : 7 jours (ticket #53) — OK ## État actuel - `src/Heimdall.Agent/Program.cs` : logging Microsoft.Extensions.Logging par défaut, pas de Serilog, pas de buffer - `AgentRegistrationService` : heartbeat `POST /api/agents/{id}/heartbeat` (API Key) toutes les 30 s avec métriques — pas de logs dans le payload - Pas de mécanisme de collecte/transmission de logs côté agent - `AgentScopedSetting` : table/settings par agent déjà en place (migration `AddAgentScopedSetting`) ## À faire 1. `LogBufferService` (singleton) : ring buffer borné en mémoire (taille configurable, ex. 500 entrées), thread-safe ; **niveau de capture effectif = override agent si défini (`AgentScopedSetting`), sinon niveau global (`agent.log.level`)** 2. Provider/custom logger `ILoggerProvider` branché sur le pipeline de logging de l'agent pour capturer les entrées (timestamp, level, message, exception, composant) sans bloquer le thread appelant 3. Endpoint dédié `POST /api/agents/{id}/logs` (API Key) envoyant le batch : `{ entries: [{ timestampUtc, level, message, exception?, source? }] }` — **ne pas alourdir le heartbeat** (découplage volume/observabilité) 4. Envoi périodique (toutes les N secondes ou attaché au tick heartbeat) avec queue bornée `DropWrite` (pas `DropOldest` — règle agent existante) et retry/backoff si échec ; les logs restent non-bloquants (jamais d'await bloquant dans le chemin de logging) 5. Sanitization des secrets avant envoi (masquer password/token/secret/API key/snapshotUrl) — spec P1 6. Si aucun log depuis X, ne rien envoyer (zéro payload = zéro bruit) ## Critères d'acceptation - [ ] Un log émis dans l'agent (Info/Warn/Error) apparaît dans le buffer puis est transmis au central en batch - [ ] Le niveau de capture suit le paramètre global, et l'override par agent (AgentScopedSetting) le remplace quand défini - [ ] L'échec d'envoi ne fait pas perdre le buffer (retry au tick suivant, pas de crash) - [ ] Les messages contenant `password=`/`token=`/`secret=` sont masqués avant transmission - [ ] L'agent tourne normalement quand le central est injoignable (logs bufferisés puis vidés, sans blocage) - [ ] Tests unitaires agent (buffer borné, drop-write, sanitization, retry) — `tests/Heimdall.Agent.Tests` ## Fichiers concernés - `src/Heimdall.Agent/Services/LogBufferService.cs` (nouveau) - `src/Heimdall.Agent/Logging/AgentLoggingProvider.cs` (nouveau) - `src/Heimdall.Agent/Program.cs` (enregistrement provider) - `src/Heimdall.Agent/AgentOptions.cs` + `appsettings.json` (niveau, taille buffer, intervalle) - `src/Heimdall.Agent/Services/AgentRegistrationService.cs` (tick d'envoi) - Settings : `AgentScopedSetting` (override par agent) + `SettingsController` (paramètre global)
Author
Owner

Décision validée : niveau de capture = paramètre central (agent.log.level) avec override possible par agent via AgentScopedSetting. Rétention 7 j validée (cf. #53). Vue globale multi-agents : hors scope pour l'instant.

Décision validée : niveau de capture = paramètre central (agent.log.level) avec override possible par agent via AgentScopedSetting. Rétention 7 j validée (cf. #53). Vue globale multi-agents : hors scope pour l'instant.
Author
Owner

Clôturé par le commit 6c5d455 (feat logs agents). Tests : 985 verts (Domain 131, Application 354, Infrastructure 163, Agent 120, Web 217).

Clôturé par le commit 6c5d455 (feat logs agents). Tests : 985 verts (Domain 131, Application 354, Infrastructure 163, Agent 120, Web 217).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nonobis/Heimdall#50
No description provided.