feat: observability, IP filtering, stdout/clickhouse fixes (v1.1.11)

- feat(observability): metrics server with /metrics and /health endpoints
- feat(observability): correlation metrics (events, success/failed, reasons, buffers)
- feat(correlation): IP exclusion filter (exact IPs and CIDR ranges)
- feat(correlation): pending orphan delay for late-arriving B events
- fix(stdout): sink is now a no-op for data; JSON must never appear on stdout
- fix(clickhouse): all flush errors were silently discarded, now properly logged
- fix(clickhouse): buffer overflow with DropOnOverflow now logged at WARN
- fix(clickhouse): retry attempts logged at WARN with attempt/delay/error context
- feat(clickhouse): connection success logged at INFO, batch sends at DEBUG
- feat(clickhouse): SetLogger() for external logger injection
- test(stdout): assert stdout remains empty for correlated and orphan logs
- chore(rpm): bump version to 1.1.11, update changelog
- docs: README and architecture.yml updated

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
toto
2026-03-05 11:40:54 +01:00
parent 68f0fcf810
commit e9dcd8ea51
16 changed files with 2035 additions and 116 deletions

166
README.md
View File

@ -71,9 +71,9 @@ docker run -d \
make package-rpm
# Installer le package RPM (Rocky Linux 8/9/10)
sudo dnf install -y dist/rpm/el8/logcorrelator-1.1.6-1.el8.x86_64.rpm
sudo dnf install -y dist/rpm/el9/logcorrelator-1.1.6-1.el9.x86_64.rpm
sudo dnf install -y dist/rpm/el10/logcorrelator-1.1.6-1.el10.x86_64.rpm
sudo dnf install -y dist/rpm/el8/logcorrelator-1.1.10-1.el8.x86_64.rpm
sudo dnf install -y dist/rpm/el9/logcorrelator-1.1.10-1.el9.x86_64.rpm
sudo dnf install -y dist/rpm/el10/logcorrelator-1.1.10-1.el10.x86_64.rpm
# Activer et démarrer le service
sudo systemctl enable logcorrelator
@ -146,6 +146,10 @@ correlation:
max_network_items: 20000
ttl:
network_ttl_s: 30
# Exclure certaines IPs source (optionnel)
exclude_source_ips:
- 10.0.0.1 # IP unique
- 192.168.0.0/16 # Plage CIDR
```
### Format du DSN ClickHouse
@ -579,3 +583,159 @@ MIT
```bash
/usr/bin/logcorrelator -config /etc/logcorrelator/logcorrelator.yml
```
## Débogage de la corrélation
### Activer les logs DEBUG
Pour diagnostiquer les problèmes de corrélation, activez le niveau de log `DEBUG` :
```yaml
# /etc/logcorrelator/logcorrelator.yml
log:
level: DEBUG
```
Les logs DEBUG affichent :
- Réception des événements A et B avec clé de corrélation et timestamp
- Tentatives de matching (succès et échecs)
- Raisons des échecs : `no_match_key`, `time_window`, `buffer_eviction`, `ttl_expired`
- Émission des orphelins (immédiats ou après délai)
- Resets TTL (mode Keep-Alive)
Exemple de logs :
```
[unixsocket:http] DEBUG event received: source=A src_ip=192.168.1.1 src_port=8080 timestamp=2026-03-04 11:00:00.123456789 +0000 UTC
[correlation] DEBUG processing A event: key=192.168.1.1:8080 timestamp=2026-03-04 11:00:00.123456789 +0000 UTC
[correlation] DEBUG A event has no matching B key in buffer: key=192.168.1.1:8080
[correlation] DEBUG A event added to pending orphans (delay=500ms): src_ip=192.168.1.1 src_port=8080
[correlation] DEBUG correlation found: A(src_ip=192.168.1.1 src_port=8080 ts=...) + B(src_ip=192.168.1.1 src_port=8080 ts=...)
```
### Serveur de métriques
Le service expose un serveur HTTP optionnel pour le monitoring et le débogage.
**Configuration :**
```yaml
metrics:
enabled: true
addr: ":8080" # Adresse d'écoute
```
**Endpoints :**
- `GET /metrics` - Retourne les métriques de corrélation au format JSON
- `GET /health` - Health check
**Métriques disponibles :**
| Métrique | Description |
|----------|-------------|
| `events_received_a` | Nombre d'événements A reçus |
| `events_received_b` | Nombre d'événements B reçus |
| `correlations_success` | Corrélations réussies |
| `correlations_failed` | Échecs de corrélation |
| `failed_no_match_key` | Échec : clé `src_ip:src_port` non trouvée |
| `failed_time_window` | Échec : hors fenêtre temporelle |
| `failed_buffer_eviction` | Échec : buffer plein |
| `failed_ttl_expired` | Échec : TTL expiré |
| `buffer_a_size` | Taille du buffer A |
| `buffer_b_size` | Taille du buffer B |
| `orphans_emitted_a` | Orphelins A émis |
| `orphans_emitted_b` | Orphelins B émis |
| `orphans_pending_a` | Orphelins A en attente |
| `pending_orphan_match` | B a corrélé avec un orphelin A en attente |
| `keepalive_resets` | Resets TTL (mode Keep-Alive) |
**Exemple de réponse :**
```json
{
"events_received_a": 150,
"events_received_b": 145,
"correlations_success": 140,
"correlations_failed": 10,
"failed_no_match_key": 5,
"failed_time_window": 3,
"failed_buffer_eviction": 0,
"failed_ttl_expired": 2,
"buffer_a_size": 10,
"buffer_b_size": 5,
"orphans_emitted_a": 10,
"keepalive_resets": 25
}
```
### Diagnostic rapide
Selon les métriques, identifiez la cause des échecs :
| Métrique élevée | Cause probable | Solution |
|----------------|----------------|----------|
| `failed_no_match_key` | Les logs A et B n'ont pas le même `src_ip + src_port` | Vérifiez que les deux sources utilisent bien la même combinaison IP/port |
| `failed_time_window` | Timestamps trop éloignés (>10s par défaut) | Augmentez `correlation.time_window.value` ou vérifiez la synchronisation des horloges |
| `failed_ttl_expired` | Les événements B expirent avant corrélation | Augmentez `correlation.ttl.network_ttl_s` |
| `failed_buffer_eviction` | Buffers trop petits pour le volume | Augmentez `correlation.buffers.max_http_items` et `max_network_items` |
| `orphans_emitted_a` élevé | Beaucoup de logs A sans B correspondant | Vérifiez que la source B envoie bien les événements attendus |
| `failed_ip_excluded` élevé | Traffic depuis des IPs exclues | Vérifiez la configuration `exclude_source_ips` |
### Exclure des IPs source
Pour exclure certains logs en fonction de l'IP source, utilisez la configuration `exclude_source_ips` :
```yaml
correlation:
exclude_source_ips:
- 10.0.0.1 # IP unique
- 192.168.1.100 # Autre IP unique
- 172.16.0.0/12 # Plage CIDR (réseau privé)
- 10.10.10.0/24 # Autre plage CIDR
```
**Cas d'usage :**
- Exclure les health checks et sondes de monitoring
- Filtrer le traffic interne connu
- Bloquer des IPs malveillantes ou indésirables
**Comportement :**
- Les événements depuis ces IPs sont silencieusement ignorés
- Ils ne sont pas corrélés, pas émis comme orphelins
- La métrique `failed_ip_excluded` compte le nombre d'événements exclus
- Les logs DEBUG montrent : `event excluded by IP filter: source=A src_ip=10.0.0.1 src_port=8080`
### Scripts de test
Deux scripts sont fournis pour tester la corrélation :
**Script Bash (simple) :**
```bash
# Test de base avec 10 paires d'événements
./scripts/test-correlation.sh -c 10 -v
# Avec chemins de sockets personnalisés
./scripts/test-correlation.sh \
-H /var/run/logcorrelator/http.socket \
-N /var/run/logcorrelator/network.socket \
-m http://localhost:8080/metrics
```
**Script Python (avancé) :**
```bash
# Installation des dépendances
pip install requests
# Test de base
python3 scripts/test-correlation-advanced.py -c 20 -v
# Tous les tests (basic, time window, different IP, keepalive)
python3 scripts/test-correlation-advanced.py --all
# Test spécifique
python3 scripts/test-correlation-advanced.py --time-window
python3 scripts/test-correlation-advanced.py --keepalive
```
**Prérequis :**
- `socat` ou `nc` (netcat) pour le script Bash
- Python 3.6+ et `requests` pour le script Python
- Le service `logcorrelator` doit être en cours d'exécution
- Le serveur de métriques doit être activé pour les vérifications automatiques