1. Le sélecteur de flux #
Obligatoire et toujours le plus précis possible.
Matchers #
{app="api"} # égalité
{app!="api"} # différent
{app=~"api|web"} # expression régulière
{namespace="prod", app=~"checkout-.*"} # plusieurs labels
{app="api", env!~"dev|test"} # exclusionErreur Courante : Un sélecteur doit contenir au moins un matcher non vide : {app=~".*"} est refusé car trop coûteux.2. Filtrer les lignes #
Du plus rapide au plus coûteux.
Filtres de ligne #
{app="api"} |= "error" # contient
{app="api"} != "healthcheck" # ne contient pas
{app="api"} |~ "timeout|refused" # regex
{app="api"} !~ "GET /static/.*" # ne correspond pas à la regex
{app="api"} |= "error" != "healthcheck" |~ "user=\\d+" # enchaînement
{app="api"} |= ip("10.0.0.0/8") # filtre sur adresse IPBonne Pratique : Mettez les filtres|=et!=avant les parsers : ils sont bien plus rapides que parser puis filtrer.
3. Parser les lignes #
Extraire des champs.
json, logfmt, pattern et regexp #
# JSON : {"level":"error","method":"GET","path":"/api","status":502,"duration_ms":340}
{app="api"} | json
{app="api"} | json level="level", http_status="status" # extraire en renommant
{app="api"} | json | status >= 500 and duration_ms > 300
# logfmt : level=error method=GET path=/api status=502
{app="api"} | logfmt | level="error"
# pattern : lignes d'accès simples (très rapide)
{app="nginx"} | pattern `<ip> - - [<_>] "<method> <uri> <_>" <status> <size>` | status >= 500
# regexp : captures nommées
{app="app"} | regexp `user=(?P<user>\w+) action=(?P<action>\w+)`Filtres sur labels extraits #
{app="api"} | json | level="error"
{app="api"} | json | status=~"5.."
{app="api"} | json | duration_ms > 250 and method="POST"
{app="api"} | json | __error__="" # ignorer les lignes non parsables
{app="api"} | logfmt | duration > 1s # durée typée (1s, 500ms)
{app="api"} | json | bytes > 5MB # taille typée4. Mettre en forme #
line_format, label_format et drop/keep.
Reformater la sortie #
{app="api"} | json | line_format "{{.method}} {{.path}} -> {{.status}} ({{.duration_ms}} ms)"
{app="api"} | json | label_format route=path, ms=duration_ms
{app="api"} | json | drop user_agent, request_id
{app="api"} | json | keep level, status, path
{app="api"} | json | line_format `{{ .level | upper }} {{ .msg | trunc 80 }}`Bonnes pratiques de performance #
- Réduire la plage de temps et le nombre de flux avant d'affiner.
- Préférer
pattern(oulogfmt) àregexp: ils sont nettement plus rapides. - Utiliser la structured metadata pour les identifiants et les filtrer sans parser.
- Limiter l'affichage avec
limit(Explore) ou--limit(logcli).
logcli query '{app="api"} |= "error" | json | status>=500' --since=30m --limit=50 --output=jsonl
logcli query '{app="api"}' --since=1h --stats # volumes lus : octets, lignes, flux