1. Les labels : la règle d'or #
Peu, stables, bornés.
Choisir ses labels #
| Bon label | Mauvais label | Pourquoi |
|---|---|---|
app, namespace, env | user_id, ip | Chaque valeur = un flux distinct |
level (5 valeurs) | request_id, trace_id | Cardinalité illimitée |
cluster, job | url complète, horodatage | Explosion du nombre de flux |
# Analyser la cardinalité
logcli series '{env="prod"}' --since=1h --analyze-labels
logcli labels pod --since=24h | wc -l
sum(loki_ingester_memory_streams)
# Déplacer l'information à forte cardinalité en structured metadata
stage.structured_metadata { values = { trace_id = "" } }Erreur Courante : Ne dépassez pas quelques dizaines de milliers de flux actifs par tenant sans dimensionner les ingesters en conséquence.
2. Des logs exploitables #
Structurer à la source.
Format et niveaux #
- Journalisez en JSON ou logfmt avec
level,msg,trace_id,service. - Une ligne = un événement ; évitez les stack traces multilignes non regroupées (
stage.multiline). - Normalisez les niveaux (
debug,info,warn,error) et réduisez le niveaudebugen production.
loki.process "app" {
forward_to = [loki.write.default.receiver]
stage.multiline { firstline = "^\\d{4}-\\d{2}-\\d{2}" max_wait_time = "3s" }
stage.json { expressions = { level = "level", trace_id = "trace_id" } }
stage.labels { values = { level = "" } }
stage.structured_metadata { values = { trace_id = "" } }
stage.drop { expression = ".*healthcheck.*" }
}3. Des requêtes rapides #
LogQL efficace.
Règles #
# ✅ Sélecteur précis + filtre de ligne AVANT le parseur
{app="checkout", env="prod"} |= "error" | json | status >= 500
# ❌ Sélecteur large puis tout filtrer après parsing
{env="prod"} | json | app="checkout" | status >= 500
# Mesurer ce qu'une requête lit
logcli query '{app="checkout"} |= "error"' --since=6h --stats
# Précalculer ce qui est demandé souvent (recording rule)
- record: app:log_errors:rate5m
expr: sum by (app) (rate({env="prod"} |= "error" [5m]))- Réduisez la plage de temps et le nombre de flux avant d'affiner.
- Préférez
patternoulogfmtàregexp. - Activez le cache des résultats et le Query Frontend pour les dashboards.
4. Coûts, sécurité et revue #
Garder la maîtrise.
Rétention et limites #
limits_config:
retention_period: 744h
retention_stream:
- { selector: '{env="dev"}', priority: 1, period: 72h }
- { selector: '{app="audit"}', priority: 2, period: 8760h }
ingestion_rate_mb: 10
per_stream_rate_limit: 5MB
max_streams_per_user: 100000
# Suivre ce qui est rejeté
sum by (reason) (rate(loki_discarded_samples_total[5m]))| Question de revue | Réponse attendue |
|---|---|
| Combien de flux actifs par tenant ? | Surveillé et borné par max_streams_per_user |
| Des données personnelles dans les logs ? | Masquées à la source (stage.replace) |
| Rétention différenciée par criticité ? | Oui (dev court, audit long) |
| Isolation entre équipes ? | Tenants distincts, authentification devant Loki |
Bonne Pratique : Mesurez le coût par application (octets ingérés) et partagez-le avec les équipes : c'est le meilleur levier pour réduire le bruit.
Schéma de référence et vérification rapide #
Visualiser le principe et le contrôler en ligne de commande.
Schéma de référence #
sum(loki_ingester_memory_streams)
logcli series '{env="prod"}' --since=1h --analyze-labels