Aller au contenu
Outils medium

Grafana Loki : centraliser les logs sans les indexer

12 min de lecture

Logo Loki

Grafana Loki centralise les logs de toute votre infrastructure et les rend consultables depuis Grafana, sans indexer leur contenu. Là où Elasticsearch indexe chaque mot, Loki n'indexe que les labels (comme Prometheus). Résultat : un déploiement rapide, un stockage réduit et un coût maîtrisé, au prix d'une recherche full-text moins poussée.

Ce guide s'adresse aux profils débutants et intermédiaires qui exploitent déjà Grafana. Vous allez démarrer Loki en local, collecter des logs avec Grafana Alloy, les interroger en LogQL et voir comment passer en production sur stockage objet.

  • Comprendre pourquoi Loki n'indexe que les labels et ce que ça change.
  • Démarrer Loki en local avec Docker, puis sur Kubernetes.
  • Collecter les logs avec Grafana Alloy, le successeur de Promtail.
  • Interroger vos logs avec le langage LogQL.
  • Éviter le piège de la cardinalité et configurer le stockage objet.

Chercher un log lors d'un incident ne devrait pas coûter le prix d'un moteur d'indexation full-text. C'est le pari de Loki : au lieu d'indexer chaque mot de chaque ligne, il n'indexe que les labels attachés aux flux de logs (le service, l'environnement, le pod). Le contenu part compressé dans un stockage objet bon marché.

Ce choix explique son positionnement et ses limites.

Problème courantRéponse de Loki
Logs éparpillés sur N serveursCentralisation via un agent (Alloy)
Coût de stockage d'ElasticsearchPas d'index full-text, stockage réduit
Corréler logs et métriquesMêmes labels que Prometheus
Apprendre un nouveau langageLogQL, proche de PromQL

Le plus simple est un conteneur unique avec un stockage sur disque. On écrit d'abord une configuration minimale de développement : authentification désactivée, anneau en mémoire, index TSDB et stockage filesystem.

loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
common:
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
replication_factor: 1
path_prefix: /loki
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
filesystem:
directory: /loki/chunks
limits_config:
retention_period: 168h # 7 jours

On lance ensuite Loki en épinglant la version, pour un résultat reproductible :

Fenêtre de terminal
docker run -d --name loki -p 3100:3100 \
-v "$(pwd)/loki-config.yaml:/etc/loki/config.yaml" \
grafana/loki:3.7.3 -config.file=/etc/loki/config.yaml

Vérification : curl http://localhost:3100/ready doit répondre ready. Sur Kubernetes, le chart Helm officiel déploie Loki en une commande :

Fenêtre de terminal
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install loki grafana/loki --namespace monitoring --create-namespace \
--set loki.auth_enabled=false --set singleBinary.replicas=1

Ce mode monolithique convient au test et aux petits volumes ; en production, on passe au mode distribué avec un stockage objet.

Loki repose sur trois briques complémentaires. Comprendre leur rôle aide à diagnostiquer un flux de logs qui n'arrive pas.

Architecture Loki : agent de collecte, Loki et Grafana

ComposantRôle
Grafana AlloyAgent qui collecte les logs et les pousse vers Loki
LokiStocke les logs, les organise par labels, répond aux requêtes
GrafanaInterface de requête et de visualisation

Loki n'indexe pas le contenu des logs, il les range par labels, exactement comme Prometheus range ses métriques. Un flux de logs est identifié par un ensemble de labels :

{namespace="production", app="frontend", pod="frontend-abc123"}

Ces labels permettent de filtrer rapidement, de corréler avec les métriques Prometheus (mêmes labels) et de réduire les coûts (pas d'index massif). Leur choix est donc décisif, et c'est aussi là que se cache le principal piège, la cardinalité, détaillé plus bas.

Grafana Alloy est l'agent de collecte recommandé, successeur de Promtail (déprécié depuis 2025). C'est un collecteur unifié, bâti sur l'OpenTelemetry Collector, qui rassemble logs, métriques et traces. On le configure en déclarant une source de logs et une destination loki.write.

L'exemple ci-dessous lit tous les fichiers .log d'un dossier, leur attache le label app, et les pousse vers Loki :

config.alloy
local.file_match "app" {
path_targets = [{"__path__" = "/logs/*.log", "app" = "demo"}]
}
loki.source.file "app" {
targets = local.file_match.app.targets
forward_to = [loki.write.default.receiver]
}
loki.write "default" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}

On lance Alloy en montant la configuration et les logs à collecter :

Fenêtre de terminal
docker run -d --name alloy \
-v "$(pwd)/config.alloy:/etc/alloy/config.alloy" \
-v "$(pwd)/logs:/logs" \
grafana/alloy:v1.17.1 \
run /etc/alloy/config.alloy

Pour d'autres sources, Alloy fournit des composants dédiés : loki.source.docker pour les conteneurs, et l'intégration Kubernetes pour collecter automatiquement les logs des pods. Le guide dédié détaille ces cas.

LogQL est le langage de requête de Loki, dans l'esprit de PromQL. On commence par sélectionner les streams via leurs labels, puis on filtre le contenu, et on peut enfin agréger.

{label="valeur"} # sélection par labels
{app="nginx"} |= "error" # contient "error"
{app="nginx"} |~ "5[0-9]{2}" # regex (codes 5xx)
{app="nginx"} != "healthcheck" # ne contient pas

Les opérateurs de filtrage se combinent avec les parseurs pour extraire des champs structurés.

OpérateurDescriptionExemple
|=Contient (exact)|= "error"
!=Ne contient pas!= "healthcheck"
|~Correspond à la regex|~ "5[0-9]{2}"
!~Ne correspond pas à la regex!~ "debug"
| jsonParse le JSON| json | level="error"
| logfmtParse le logfmt| logfmt | duration > 100

Quelques requêtes concrètes :

# Toutes les erreurs du frontend en production
{namespace="production", app="frontend"} |= "error"
# Parser un log JSON et filtrer sur un champ
{app="nginx"} | json | status_code = 500
# Compter les erreurs par minute
count_over_time({app="api"} |= "error" [1m])

Loki n'a pas d'interface propre : il se consulte depuis Grafana, où il devient une source de données. La configuration prend moins d'une minute.

  1. Ouvrir Grafana sur http://localhost:3000 (identifiants par défaut admin / admin).

  2. Ajouter la source : menu Connexions, Data sources, Add data source, choisir Loki.

  3. Renseigner l'URL : http://loki:3100 sur Kubernetes, ou l'adresse de votre conteneur.

  4. Valider avec « Save & test », qui confirme la connexion.

  5. Explorer : dans Explore, tapez {job=~".+"} pour voir remonter vos premiers logs.

En production, le filesystem local ne convient pas : un seul nœud, pas de réplication, disque qui se remplit. On bascule le storage_config vers un stockage objet (S3, GCS ou MinIO) et on adapte la rétention.

schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
storage_config:
aws:
s3: s3://eu-west-3/mon-bucket-loki
s3forcepathstyle: true
tsdb_shipper:
active_index_directory: /loki/tsdb-index
cache_location: /loki/tsdb-cache
limits_config:
retention_period: 336h # 14 jours

Trois réglages comptent : le backend objet pour le volume, la rétention pour maîtriser le coût, et les limites d'ingestion pour qu'un service bavard ne sature pas la plateforme.

La cardinalité est l'ennemi numéro un de Loki. Chaque combinaison unique de labels crée un stream distinct. Utiliser un identifiant à forte variété (un request_id, un user_id) comme label génère des millions de streams et effondre les performances.

La règle est simple : les labels décrivent la provenance (namespace, app, pod), pas le contenu. Les données à forte cardinalité restent dans le corps du log, où LogQL les extrait à la demande avec | json ou | logfmt. On garde ainsi un nombre de streams raisonnable tout en pouvant filtrer finement.

La plupart des incidents Loki tiennent à la collecte ou à la cardinalité. Voici les symptômes les plus fréquents.

SymptômeCause probableSolution
connection refused sur :3100Loki non démarréVérifier docker logs loki
Aucun log dans GrafanaL'agent ne pousse pasVérifier l'url de loki.write dans Alloy
rate limited à l'ingestionTrop de logs ou de labelsAugmenter limits_config.ingestion_rate_mb
Requêtes lentesTrop de streamsRéduire la cardinalité des labels
Fenêtre de terminal
# L'agent voit-il Loki ?
curl http://localhost:3100/ready
# Quels labels Loki connaît-il déjà ?
curl http://localhost:3100/loki/api/v1/labels
  1. Loki n'indexe que les labels, pas le contenu : stockage réduit, coût maîtrisé.
  2. Les labels sont partagés avec Prometheus : logs et métriques se corrèlent naturellement.
  3. Grafana Alloy remplace Promtail comme agent de collecte, déprécié depuis 2025.
  4. LogQL sélectionne des streams par labels, puis filtre et agrège le contenu.
  5. La cardinalité est le piège : jamais d'identifiant unique en label, données à variété dans le corps du log.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn