← retour aux snippets

stdbuf: sortie temps réel des pipelines

Forcer le flush ligne par ligne pour grep/sed/awk et obtenir des logs temps réel fiables dans vos pipes.

objectif

Éviter les retards d’affichage dans les pipelines (buffering) en forçant un flush par ligne avec stdbuf. Idéal pour suivre en direct les logs tout en filtrant/transformant.

code minimal

# suivre les 500/502 en temps réel sans latence de grep/awk
tail -F /var/log/nginx/data.pm/access.log \
  | stdbuf -oL -eL grep -E ' (500|502) ' \
  | stdbuf -oL -eL awk '{print strftime("%FT%TZ"), $0}'

utilisation

# 1) pipeline complet: tail -> grep -> sed -> awk (tout en ligne-buffered)
tail -F /var/log/nginx/data.pm/access.log \
  | stdbuf -oL -eL grep -E ' (4[0-9]{2}|5[0-9]{2}) ' \
  | stdbuf -oL -eL sed -E 's/([0-9]{3})$/\1 ERROR/' \
  | stdbuf -oL -eL awk '{print strftime("%F %T"), $0}'

# 2) flux JSON de api.data.pm, extraction clé et affichage instantané
curl -fsS https://api.data.pm/stream/events \
  | stdbuf -oL -eL jq -c '. | {ts, type}'

# 3) scripts qui bufferisent: Python (-u) ou node (via stdbuf)
python3 -u scripts/consume_api.py \
  | stdbuf -oL -eL jq -r '.message'

stdbuf -oL -eL node scripts/parse-log.js \
  | stdbuf -oL -eL grep error

# 4) greps portables: GNU grep (--line-buffered) quand dispo
tail -F /var/log/nginx/data.pm/error.log \
  | grep --line-buffered -i 'timeout' \
  | stdbuf -oL -eL awk '{print strftime("%FT%TZ"), $0}'

# 5) watcher build: relayer les sorties d'un build verbeux sans délai
stdbuf -oL -eL npm run build \
  | stdbuf -oL -eL tee /tmp/build.log

variante(s) utile(s)

# macOS: stdbuf via coreutils (gstdbuf), sinon expect "unbuffer"
# brew install coreutils expect
tail -F /usr/local/var/log/data.pm/access.log \
  | gstdbuf -oL -eL ggrep -E ' (500|502) ' \
  | gstdbuf -oL -eL awk '{print strftime("%FT%TZ"), $0}'

# forcer un flush immédiat (non recommandé sauf debug intense)
# -o0/-e0 = pas de buffer (peut être coûteux CPU)
tail -F /var/log/nginx/data.pm/access.log \
  | stdbuf -o0 -e0 grep -i error

# services qui ne flushent pas: ajouter stdbuf au lancement
# (ex: unit systemd pour une app qui écrit sur stdout)
# ExecStart=/usr/bin/env stdbuf -oL -eL /usr/local/bin/app

# limiter le bruit en batchant localement mais en gardant le "live" (awk)
tail -F /var/log/nginx/data.pm/access.log \
  | stdbuf -oL -eL awk 'NR%10==0{fflush();} {print}'

# diagnostiquer qui bufferise: insérer des marqueurs temporels
producer | stdbuf -oL -eL awk '{print strftime("%T"), $0}'

notes

  • Le buffering retarde l’affichage quand la sortie va vers un pipe. stdbuf -oL -eL force un flush par ligne sur stdout/stderr.
  • Appliquez stdbuf à chaque étape du pipeline qui lit/écrit (grep, sed, awk, node, etc.). Le premier producteur (ex: tail -F) n’a pas besoin d’ajustement.
  • Certains outils ont des options natives: GNU grep --line-buffered, Python -u (unbuffered), PYTHONUNBUFFERED=1.
  • -o0/-e0 désactive totalement le buffer (debug ponctuel). Préférez -oL/-eL pour un bon compromis.
  • macOS: utilisez gstdbuf (coreutils) ou unbuffer (expect). BSD grep n’a pas --line-buffered; installez ggrep.