service: name: logcorrelator context: http-network-correlation language: go pattern: hexagonal description: > logcorrelator est un service système (lancé par systemd) écrit en Go, chargé de recevoir deux flux de logs JSON via des sockets Unix, de corréler les événements HTTP applicatifs (source A, typiquement Apache ou reverse proxy) avec des événements réseau (source B, métadonnées IP/TCP, JA3/JA4, etc.) sur la base de la combinaison strictement définie src_ip + src_port, avec une fenêtre temporelle configurable. Le service supporte les connexions HTTP Keep-Alive : un log réseau peut être corrélé à plusieurs logs HTTP successifs (stratégie 1‑à‑N). La rétention en mémoire est bornée par des tailles de caches configurables et un TTL dynamique pour la source B. Le service émet toujours les événements A même lorsqu'aucun événement B n'est disponible, n'émet jamais de logs B seuls, et pousse les résultats vers ClickHouse et/ou un fichier local. Fonctionnalités de débogage incluses : - Serveur de métriques HTTP (/metrics, /health) - Logs DEBUG détaillés avec raisons des échecs de corrélation - Filtrage des IPs source (exclude_source_ips) - Scripts de test (Bash et Python) - Métriques : événements reçus, corrélations, échecs par raison, buffers, orphelins runtime: deployment: unit_type: systemd description: > logcorrelator est livré sous forme de binaire autonome, exécuté comme un service systemd. L'unité systemd assure le démarrage automatique au boot, le redémarrage en cas de crash, et une intégration standard dans l'écosystème Linux. binary_path: /usr/bin/logcorrelator config_path: /etc/logcorrelator/logcorrelator.yml user: logcorrelator group: logcorrelator restart: on-failure systemd_unit: path: /etc/systemd/system/logcorrelator.service content_example: | [Unit] Description=logcorrelator service After=network.target [Service] Type=simple User=logcorrelator Group=logcorrelator ExecStart=/usr/bin/logcorrelator -config /etc/logcorrelator/logcorrelator.yml ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure RestartSec=5 # Security hardening NoNewPrivileges=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/log/logcorrelator /var/run/logcorrelator /etc/logcorrelator # Resource limits LimitNOFILE=65536 # Systemd timeouts TimeoutStartSec=10 TimeoutStopSec=30 [Install] WantedBy=multi-user.target os: supported: - rocky-linux-8 - rocky-linux-9 - almalinux-10 - autres-linux-recentes logs: stdout_stderr: journald structured: true description: > Les logs internes du service (erreurs, messages d'information) sont envoyés vers stdout/stderr et collectés par journald. Ils sont structurés et ne contiennent pas de données personnelles. signals: graceful_shutdown: - SIGINT - SIGTERM reload: - SIGHUP description: > SIGINT/SIGTERM : arrêt propre (arrêt des sockets, vidage des buffers, fermeture des sinks). SIGHUP : réouverture des fichiers de sortie (utile pour la rotation des logs via logrotate) sans arrêter le service. filesystem: description: > Permissions et propriété des fichiers et répertoires utilisés par logcorrelator. directories: - path: /var/run/logcorrelator owner: logcorrelator:logcorrelator permissions: "0755" purpose: > Contient les sockets Unix (http.socket, network.socket). Les sockets sont créés avec des permissions 0666 (world read/write). - path: /var/log/logcorrelator owner: logcorrelator:logcorrelator permissions: "0750" purpose: > Contient les logs corrélés (correlated.log). - path: /var/lib/logcorrelator owner: logcorrelator:logcorrelator permissions: "0750" purpose: > Répertoire home du service (données internes). - path: /etc/logcorrelator owner: logcorrelator:logcorrelator permissions: "0750" purpose: > Contient la configuration (logcorrelator.yml, logcorrelator.yml.example). files: - path: /etc/logcorrelator/logcorrelator.yml owner: logcorrelator:logcorrelator permissions: "0640" rpm_directive: "%config(noreplace)" - path: /etc/logcorrelator/logcorrelator.yml.example owner: logcorrelator:logcorrelator permissions: "0640" - path: /etc/systemd/system/logcorrelator.service owner: root:root permissions: "0644" - path: /etc/logrotate.d/logcorrelator owner: root:root permissions: "0644" rpm_directive: "%config(noreplace)" sockets: - path: /var/run/logcorrelator/http.socket owner: logcorrelator:logcorrelator permissions: "0666" type: unix_datagram purpose: "Source A - logs HTTP applicatifs" - path: /var/run/logcorrelator/network.socket owner: logcorrelator:logcorrelator permissions: "0666" type: unix_datagram purpose: "Source B - logs réseau" packaging: description: > logcorrelator est distribué sous forme de packages .rpm (Rocky Linux, AlmaLinux, RHEL), construits intégralement dans des conteneurs. Le changelog RPM est mis à jour à chaque changement de version. Tous les numéros de version doivent être cohérents entre le spec RPM, le Makefile (PKG_VERSION), le CHANGELOG.md et les tags git. Politique de mise à jour de la configuration : - Le fichier logcorrelator.yml est marqué %config(noreplace) : il n'est JAMAIS écrasé lors d'une mise à jour. La configuration existante est préservée. - Le fichier logcorrelator.yml.example est TOUJOURS mis à jour pour refléter les nouvelles options de configuration disponibles. - Lors de la première installation, si logcorrelator.yml n'existe pas, il est créé à partir de logcorrelator.yml.example. formats: - rpm target_distros: - rocky-linux-8 - rocky-linux-9 - almalinux-10 - rhel-8 - rhel-9 - rhel-10 rpm: tool: fpm changelog: source: git # ou CHANGELOG.md description: > À chaque build, un script génère un fichier de changelog RPM à partir de l'historique (tags/commits) et le passe à fpm (option --rpm-changelog). contents: - path: /usr/bin/logcorrelator type: binary - path: /etc/logcorrelator/logcorrelator.yml type: config directives: "%config(noreplace)" behavior: > Jamais écrasé lors des mises à jour. Préservé automatiquement par RPM. Créé uniquement lors de la première installation s'il n'existe pas. - path: /etc/logcorrelator/logcorrelator.yml.example type: doc behavior: > TOUJOURS mis à jour lors des mises à jour. Sert de référence pour les nouvelles options de configuration disponibles. - path: /etc/systemd/system/logcorrelator.service type: systemd_unit - path: /etc/logrotate.d/logcorrelator type: logrotate_script directives: "%config(noreplace)" logrotate_example: | /var/log/logcorrelator/correlated.log { daily rotate 7 compress delaycompress missingok notifempty create 0640 logcorrelator logcorrelator sharedscripts postrotate /bin/systemctl reload logcorrelator > /dev/null 2>&1 || true endscript } config: format: yaml location: /etc/logcorrelator/logcorrelator.yml reload_strategy: signal_sighup_for_files description: > Toute la configuration est centralisée dans un fichier YAML lisible. Le RPM fournit aussi un fichier d'exemple mis à jour à chaque version. example: | # /etc/logcorrelator/logcorrelator.yml log: level: INFO # DEBUG, INFO, WARN, ERROR inputs: unix_sockets: # Source HTTP (A) : logs applicatifs en JSON, 1 datagramme = 1 log. - name: http source_type: A path: /var/run/logcorrelator/http.socket format: json socket_permissions: "0666" # Source réseau (B) : logs IP/TCP/JA3... en JSON, 1 datagramme = 1 log. - name: network source_type: B path: /var/run/logcorrelator/network.socket format: json socket_permissions: "0666" outputs: file: enabled: true path: /var/log/logcorrelator/correlated.log clickhouse: enabled: false dsn: clickhouse://user:pass@localhost:9000/db table: correlated_logs_http_network batch_size: 500 flush_interval_ms: 200 max_buffer_size: 5000 drop_on_overflow: true async_insert: true timeout_ms: 1000 stdout: enabled: false level: INFO # DEBUG: tous les logs (y compris orphelins), INFO: seulement corrélés, WARN: corrélés seulement, ERROR: aucun correlation: # Fenêtre de corrélation : si le log HTTP arrive avant le réseau, il attend # au plus cette durée (sauf éviction du cache HTTP). # Augmentée à 10s pour supporter le Keep-Alive HTTP. time_window: value: 10 unit: s orphan_policy: apache_always_emit: true # Toujours émettre les événements A, même sans correspondance B network_emit: false # Ne jamais émettre les événements B seuls matching: mode: one_to_many # Keep‑Alive : un B peut corréler plusieurs A. buffers: # Tailles max des caches en mémoire (en nombre de logs). max_http_items: 10000 max_network_items: 20000 ttl: # Durée de vie standard d'un log réseau (B) en mémoire. Chaque corrélation # réussie avec un A réinitialise ce TTL. # Augmenté à 120s pour supporter les sessions HTTP Keep-Alive longues. network_ttl_s: 120 # Filtrage des IPs source à exclure (optionnel) exclude_source_ips: - 10.0.0.1 # IP unique - 172.16.0.0/12 # Plage CIDR # Les événements depuis ces IPs sont silencieusement ignorés # Serveur de métriques HTTP (optionnel, pour débogage et monitoring) metrics: enabled: false addr: ":8080" # Adresse d'écoute du serveur HTTP # Endpoints: # GET /metrics - Retourne les métriques de corrélation en JSON # GET /health - Health check inputs: description: > Deux flux de logs JSON via sockets Unix datagram (SOCK_DGRAM). Chaque datagramme contient un JSON complet. Le champ source_type ("A" ou "B") doit être spécifié pour chaque socket. À défaut, la source est déduite automatiquement (présence de headers = source A, sinon source B). unix_sockets: - name: http id: A description: > Source A, logs HTTP applicatifs (Apache, reverse proxy, etc.). Schéma JSON variable, champ timestamp (int64, nanosecondes) obligatoire, headers dynamiques (header_*). path: /var/run/logcorrelator/http.socket source_type: A permissions: "0666" protocol: unix socket_type: dgram mode: datagram format: json framing: message max_datagram_bytes: 65535 retry_on_error: true - name: network id: B description: > Source B, logs réseau (métadonnées IP/TCP, JA3/JA4, etc.). Seuls src_ip et src_port sont requis pour la corrélation. Le champ timestamp est optionnel ; s'il est absent, l'heure de réception est utilisée. path: /var/run/logcorrelator/network.socket source_type: B permissions: "0666" protocol: unix socket_type: dgram mode: datagram format: json framing: message max_datagram_bytes: 65535 retry_on_error: true outputs: description: > Les logs corrélés sont envoyés vers un ou plusieurs sinks (MultiSink). sinks: file: enabled: true description: > Sink fichier local. Un JSON par ligne. Rotation gérée par logrotate, réouverture du fichier sur SIGHUP. path: /var/log/logcorrelator/correlated.log format: json_lines rotate_managed_by: external_logrotate clickhouse: enabled: false description: > Sink principal pour l'archivage et l'analyse quasi temps réel. Inserts batch asynchrones, drop en cas de saturation. Le service insère uniquement dans une table RAW (raw_json String, ingest_time DateTime DEFAULT now()). La table parsée et la vue matérialisée sont gérées en externe (DDL séparés). Toutes les erreurs de connexion, de flush et de retry sont loggées : INFO à la connexion, ERROR sur échec de flush, WARN sur drop/retry, DEBUG sur envoi réussi. dsn: clickhouse://user:pass@host:9000/db table: correlated_logs_http_network batch_size: 500 flush_interval_ms: 200 max_buffer_size: 5000 drop_on_overflow: true async_insert: true timeout_ms: 1000 stdout: enabled: false description: > Sink no-op pour les données. Aucune donnée corrélée ou orpheline n'est jamais écrite sur stdout. Ce sink existe uniquement pour satisfaire l'interface CorrelatedLogSink. Les logs opérationnels du service (démarrage, erreurs, métriques de débogage) sont toujours sur stderr via observability.Logger, indépendamment de ce sink. correlation: description: > Corrélation stricte basée sur src_ip + src_port et une fenêtre temporelle configurable. Aucun autre champ n'est utilisé pour la décision de corrélation. key: - src_ip - src_port time_window: value: 10 unit: s description: > Fenêtre de temps appliquée aux timestamps de A et B. Si B n'arrive pas dans ce délai, A est émis comme orphelin. Augmentée à 10s pour le Keep-Alive. retention_limits: max_http_items: 10000 max_network_items: 20000 description: > Limites des caches. Si max_http_items est atteint, le plus ancien A est évincé et émis orphelin. Si max_network_items est atteint, le plus ancien B est supprimé silencieusement. ttl_management: network_ttl_s: 120 description: > TTL des logs réseau. Chaque fois qu'un B est corrélé à un A (Keep-Alive), son TTL est remis à cette valeur. Augmenté à 120s pour les sessions longues. timestamp_source: apache: timestamp (champ int64, nanosecondes) network: timestamp (champ int64, nanosecondes) si présent, sinon time (RFC3339), sinon reception_time (time.Now()) orphan_policy: apache_always_emit: true network_emit: false matching: mode: one_to_many description: > Stratégie 1‑à‑N : un log réseau peut être utilisé pour plusieurs logs HTTP successifs tant qu'il n'a pas expiré ni été évincé. schema: description: > Schémas variables pour A et B. Quelques champs seulement sont obligatoires pour la corrélation, les autres sont acceptés sans modification de code. source_A: description: > Logs HTTP applicatifs au format JSON. required_fields: - name: src_ip type: string - name: src_port type: int - name: timestamp type: int64 unit: ns optional_fields: - name: dst_ip type: string - name: dst_port type: int - name: method type: string - name: path type: string - name: host type: string - name: http_version type: string dynamic_fields: - pattern: header_* target_map: headers - pattern: "*" target_map: extra source_B: description: Logs réseau JSON (IP/TCP, JA3/JA4...). required_fields: - name: src_ip type: string - name: src_port type: int optional_fields: - name: dst_ip type: string - name: dst_port type: int - name: timestamp type: int64 unit: ns - name: time type: string format: RFC3339 ou RFC3339Nano dynamic_fields: - pattern: "*" target_map: extra normalized_event: description: > Représentation interne unifiée des événements A/B. fields: - name: source type: enum("A","B") - name: timestamp type: time.Time - name: src_ip type: string - name: src_port type: int - name: dst_ip type: string optional: true - name: dst_port type: int optional: true - name: headers type: map[string]string optional: true - name: extra type: map[string]any correlated_log: description: > Structure du log corrélé émis vers les sinks. fields: - name: timestamp type: time.Time - name: src_ip type: string - name: src_port type: int - name: dst_ip type: string optional: true - name: dst_port type: int optional: true - name: correlated type: bool - name: orphan_side type: string - name: "*" type: map[string]any clickhouse_schema: strategy: external_ddls database: mabase_prod description: > La table ClickHouse est gérée en dehors du service. Le service insère dans une table RAW avec une seule colonne raw_json contenant le log corrélé complet sérialisé en JSON. La colonne ingest_time utilise DEFAULT now(). Toute extraction de champs (table parsée, vue matérialisée) est gérée en externe via des DDL séparés, non implémentés dans le service. tables: - name: http_logs_raw description: > Table d'ingestion brute. Une seule colonne raw_json contient le log corrélé complet sérialisé en JSON. La colonne ingest_time est auto-générée avec DEFAULT now(). Partitionnée par jour pour optimiser le TTL. engine: MergeTree partition_by: toDate(ingest_time) order_by: ingest_time columns: - name: raw_json type: String - name: ingest_time type: DateTime default: now() insert_format: | INSERT INTO mabase_prod.http_logs_raw (raw_json) VALUES ('{...log corrélé sérialisé en JSON...}') notes: > Le service utilise l'API native clickhouse-go/v2 (PrepareBatch + Append + Send). La colonne ingest_time n'est PAS explicitement insérée (DEFAULT now() est utilisé). - name: http_logs description: > Table parsée (optionnelle, gérée en externe). Le service n'implémente PAS l'extraction des champs suivants. Si cette table est utilisée, elle doit être alimentée par une vue matérialisée ou un traitement ETL externe. engine: MergeTree partition_by: log_date order_by: (time, src_ip, dst_ip, ja4) columns: - name: time type: DateTime - name: log_date type: Date default: toDate(time) - name: src_ip type: IPv4 - name: src_port type: UInt16 - name: dst_ip type: IPv4 - name: dst_port type: UInt16 - name: method type: LowCardinality(String) - name: scheme type: LowCardinality(String) - name: host type: LowCardinality(String) - name: path type: String - name: query type: String - name: http_version type: LowCardinality(String) - name: orphan_side type: LowCardinality(String) - name: correlated type: UInt8 - name: keepalives type: UInt16 status: non_implémenté - name: a_timestamp type: UInt64 status: non_implémenté - name: b_timestamp type: UInt64 status: non_implémenté - name: conn_id type: String status: non_implémenté - name: ip_meta_df type: UInt8 status: non_implémenté - name: ip_meta_id type: UInt32 status: non_implémenté - name: ip_meta_total_length type: UInt32 status: non_implémenté - name: ip_meta_ttl type: UInt8 status: non_implémenté - name: tcp_meta_options type: LowCardinality(String) status: non_implémenté - name: tcp_meta_window_size type: UInt32 status: non_implémenté - name: syn_to_clienthello_ms type: Int32 status: non_implémenté - name: tls_version type: LowCardinality(String) status: non_implémenté - name: tls_sni type: LowCardinality(String) status: non_implémenté - name: ja3 type: String status: non_implémenté - name: ja3_hash type: String status: non_implémenté - name: ja4 type: String status: non_implémenté - name: header_user_agent type: String status: non_implémenté - name: header_accept type: String status: non_implémenté - name: header_accept_encoding type: String status: non_implémenté - name: header_accept_language type: String status: non_implémenté - name: header_x_request_id type: String status: non_implémenté - name: header_x_trace_id type: String status: non_implémenté - name: header_x_forwarded_for type: String status: non_implémenté - name: header_sec_ch_ua type: String status: non_implémenté - name: header_sec_ch_ua_mobile type: String status: non_implémenté - name: header_sec_ch_ua_platform type: String status: non_implémenté - name: header_sec_fetch_dest type: String status: non_implémenté - name: header_sec_fetch_mode type: String status: non_implémenté - name: header_sec_fetch_site type: String status: non_implémenté notes: > Cette table et la vue matérialisée associée sont gérées en externe (DDL séparés). Le service se contente d'insérer le JSON brut dans http_logs_raw. Les champs marqués "non_implémenté" ne sont PAS extraits par le service. users: description: > La gestion des utilisateurs ClickHouse est externe au service. Le DSN est configuré dans le fichier de configuration YAML. notes: > Cette section est fournie à titre indicatif pour l'administration ClickHouse. migration: description: > Aucune migration n'est implémentée dans le service. La gestion des schémas (tables, vues matérialisées) est entièrement externe (DDL séparés). architecture: description: > Architecture hexagonale : domaine de corrélation indépendant, ports abstraits pour les sources/sinks, adaptateurs pour sockets Unix, fichier, ClickHouse et stdout, couche application d'orchestration, et modules infra (config, observabilité). modules: - name: cmd/logcorrelator type: entrypoint responsibilities: - Chargement de la configuration YAML. - Initialisation des adaptateurs d'entrée/sortie. - Création du CorrelationService. - Démarrage de l'orchestrateur. - Gestion des signaux (SIGINT, SIGTERM, SIGHUP). - Versioning via -ldflags (main.Version). - name: internal/domain type: domain responsibilities: - Modèles NormalizedEvent et CorrelatedLog. - CorrelationService (fenêtre, TTL, buffers bornés, one-to-many/Keep-Alive, orphelins). - Custom JSON marshaling pour CorrelatedLog (structure plate). - name: internal/ports type: ports responsibilities: - Interfaces EventSource, CorrelatedLogSink, CorrelationProcessor. - name: internal/app type: application responsibilities: - Orchestrator : EventSource → CorrelationService → MultiSink. - Gestion du contexte de shutdown et drain des événements. - name: internal/adapters/inbound/unixsocket type: adapter_inbound responsibilities: - Lecture Unix datagram (SOCK_DGRAM) et parsing JSON → NormalizedEvent. - Détection automatique de la source (A/B) via source_type ou headers. - Gestion des permissions de socket (défaut 0666). - Cleanup du fichier socket à l'arrêt. - name: internal/adapters/outbound/file type: adapter_outbound responsibilities: - Écriture JSON lines. - Réouverture du fichier sur SIGHUP (log rotation). - Validation des chemins (répertoire autorisé). - name: internal/adapters/outbound/clickhouse type: adapter_outbound responsibilities: - Bufferisation + inserts batch asynchrones. - Gestion du drop_on_overflow. - Retry avec backoff exponentiel (MaxRetries=3). - API native clickhouse-go/v2 (PrepareBatch + Append + Send). - Logging complet via observability.Logger (SetLogger) : INFO à la connexion, DEBUG sur envoi réussi (rows/table), WARN sur drop buffer et retries, ERROR sur échec de flush (périodique, batch, fermeture). - name: internal/adapters/outbound/stdout type: adapter_outbound responsibilities: - Sink no-op pour les données corrélées. - Write/Flush/Close ne font rien : les données ne passent jamais par stdout. - Les logs opérationnels sont sur stderr via observability.Logger (indépendant de ce sink). - name: internal/adapters/outbound/multi type: adapter_outbound responsibilities: - Fan-out vers plusieurs sinks. - Implémentation de Reopen() pour la rotation des logs. - name: internal/config type: infrastructure responsibilities: - Chargement/validation de la configuration YAML. - Valeurs par défaut et fallback pour champs dépréciés. - name: internal/observability type: infrastructure responsibilities: - Logger structuré avec niveaux (DEBUG, INFO, WARN, ERROR). - CorrelationMetrics : suivi des statistiques de corrélation. - MetricsServer : serveur HTTP pour exposition des métriques (/metrics, /health). - Traçage des événements exclus (exclude_source_ips). - Logs pour : événements reçus, corrélations, orphelins, buffer plein. testing: unit: description: > Tests unitaires table‑driven, couverture cible ≥ 80 %. La couverture actuelle est d'environ 74-80% selon les versions. Les tests se concentrent sur la logique de corrélation, les caches, les sinks et le parsing des datagrammes. coverage_minimum: 0.8 coverage_actual: ~0.74-0.80 focus: - CorrelationService (fenêtre, TTL, évictions, one-to-many/Keep-Alive) - Parsing A/B → NormalizedEvent (datagrammes JSON) - ClickHouseSink (batching, retry, overflow, logging erreurs/succès) - FileSink (réouverture sur SIGHUP) - MultiSink (fan-out) - StdoutSink (no-op data, test stdout reste vide) - Config (validation, valeurs par défaut, exclude_source_ips) - UnixSocketSource (lecture, permissions, cleanup) - CorrelationMetrics (suivi des statistiques) - MetricsServer (endpoints /metrics et /health) integration: description: > Tests d'intégration limités. Le flux complet A+B → corrélation → sinks est testé via des tests unitaires avec mocks. ClickHouse est mocké (pas de tests avec vrai ClickHouse). Scénarios Keep-Alive testés dans correlation_service_test.go. Scripts de test fournis : scripts/test-correlation.sh et scripts/test-correlation-advanced.py. docker: description: > Build, tests et packaging RPM sont exécutés intégralement dans des conteneurs via un multi‑stage build. Deux Dockerfiles : Dockerfile (build + runtime + dev) et Dockerfile.package (RPM multi-distros : el8, el9, el10). build_pipeline: multi_stage: true stages: - name: builder base: golang:1.21 description: > go test -race -coverprofile=coverage.txt ./... avec vérification de couverture (échec si < 80 %). Compilation d'un binaire statique (CGO_ENABLED=0, GOOS=linux, GOARCH=amd64). - name: runtime base: scratch description: > Image minimale contenant uniquement le binaire et la config exemple. - name: rpm_builder_el8 base: rockylinux:8 description: > Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 8. - name: rpm_builder_el9 base: rockylinux:9 description: > Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 9. - name: rpm_builder_el10 base: almalinux:10 description: > Installation de fpm (via Ruby), construction RPM pour Enterprise Linux 10. - name: output_export base: alpine:latest description: > Export des paquets RPM produits pour les 3 distributions (el8, el9, el10). files: - path: Dockerfile description: Build principal (builder, runtime, dev) et packaging RPM mono-distro. - path: Dockerfile.package description: Packaging RPM multi-distros (el8, el9, el10) avec scripts post/preun/postun. observability: description: > Le service inclut des fonctionnalités complètes de débogage et de monitoring pour diagnostiquer les problèmes de corrélation et surveiller les performances. logging: levels: - DEBUG: Tous les événements reçus, tentatives de corrélation, raisons des échecs - INFO: Événements corrélés, démarrage/arrêt du service - WARN: Orphelins émis, buffer plein, TTL expiré - ERROR: Erreurs de parsing, échecs de sink, erreurs critiques debug_logs: - "event received: source=A src_ip=192.168.1.1 src_port=8080 timestamp=..." - "processing A event: key=192.168.1.1:8080 timestamp=..." - "correlation found: A(src_ip=... src_port=... ts=...) + B(src_ip=... src_port=... ts=...)" - "A event has no matching B key in buffer: key=..." - "A event has same key as B but outside time window: key=... time_diff=5s window=10s" - "event excluded by IP filter: source=A src_ip=10.0.0.1 src_port=8080" - "TTL reset for B event (Keep-Alive): key=... new_ttl=120s" - "[clickhouse] DEBUG batch sent: rows=42 table=correlated_logs_http_network" info_logs: - "[clickhouse] INFO connected to ClickHouse: table=... batch_size=500 flush_interval_ms=200" warn_logs: - "[clickhouse] WARN buffer full, dropping log: table=... buffer_size=5000" - "[clickhouse] WARN retrying batch insert: attempt=2/3 delay=100ms rows=42 err=connection refused" error_logs: - "[clickhouse] ERROR periodic flush failed: ..." - "[clickhouse] ERROR batch flush failed: ..." - "[clickhouse] ERROR final flush on close failed: ..." metrics_server: enabled: true endpoints: - path: /metrics method: GET description: Retourne les métriques de corrélation au format JSON response_example: | { "events_received_a": 1542, "events_received_b": 1498, "correlations_success": 1450, "correlations_failed": 92, "failed_no_match_key": 45, "failed_time_window": 23, "failed_buffer_eviction": 5, "failed_ttl_expired": 12, "failed_ip_excluded": 7, "buffer_a_size": 23, "buffer_b_size": 18, "orphans_emitted_a": 92, "keepalive_resets": 892 } - path: /health method: GET description: Health check response_example: | {"status":"healthy"} metrics_tracked: events_received: - events_received_a: Nombre d'événements HTTP (source A) reçus - events_received_b: Nombre d'événements réseau (source B) reçus correlations: - correlations_success: Corrélations réussies - correlations_failed: Échecs de corrélation failure_reasons: - failed_no_match_key: Clé src_ip:src_port non trouvée dans le buffer - failed_time_window: Événements hors fenêtre temporelle - failed_buffer_eviction: Buffer plein, événement évincé - failed_ttl_expired: TTL du événement B expiré - failed_ip_excluded: Événement exclu par filtre IP (exclude_source_ips) buffers: - buffer_a_size: Taille actuelle du buffer HTTP - buffer_b_size: Taille actuelle du buffer réseau orphans: - orphans_emitted_a: Orphelins A émis (sans correspondance B) - orphans_emitted_b: Orphelins B émis (toujours 0, policy: network_emit=false) - orphans_pending_a: Orphelins A en attente (délai avant émission) - pending_orphan_match: B a corrélé avec un orphelin A en attente keepalive: - keepalive_resets: Resets TTL pour mode Keep-Alive (one-to-many) troubleshooting: description: > Guide de diagnostic basé sur les métriques et logs common_issues: - symptom: failed_no_match_key élevé cause: Les logs A et B n'ont pas le même src_ip + src_port solution: Vérifier que les deux sources utilisent la même combinaison IP/port - symptom: failed_time_window élevé cause: Timestamps trop éloignés (> time_window.value) solution: Augmenter correlation.time_window.value ou synchroniser les horloges (NTP) - symptom: failed_ttl_expired élevé cause: Les événements B expirent avant corrélation solution: Augmenter correlation.ttl.network_ttl_s - symptom: failed_buffer_eviction élevé cause: Buffers trop petits pour le volume de logs solution: Augmenter correlation.buffers.max_http_items et max_network_items - symptom: failed_ip_excluded élevé cause: Traffic depuis des IPs configurées dans exclude_source_ips solution: Vérifier la configuration, c'est normal si attendu - symptom: orphans_emitted_a élevé cause: Beaucoup de logs A sans correspondance B solution: Vérifier que la source B envoie bien les événements attendus test_scripts: - name: scripts/test-correlation.sh description: Script Bash pour tester la corrélation avec des événements synthétiques features: - Envoi de paires A+B avec mêmes src_ip:src_port - Vérification des métriques avant/après - Options: -c (count), -d (delay), -v (verbose), -m (metrics-url) - name: scripts/test-correlation-advanced.py description: Script Python avancé avec multiples scénarios de test features: - Basic test: corrélations simples - Time window test: vérifie l'expiration de la fenêtre temporelle - Different IP test: vérifie non-corrélation avec IPs différentes - Keep-Alive test: vérifie le mode one-to-many - Métriques en temps réel