Jouer avec jq, json, ndjson

Jouons avec un flux ndjson qu'on parsera et filtrera avec l'outil jq.

Prenons un fichier de log log.ndjson ressemblant à ceci :

1{"ts":"2023-09-12T10:58:11+02:00","src":"hostname.example","app":"default-app","lvl":"INFO","msg":"DEBUT"}
2{"ts":"2023-09-12T11:58:11+02:00","src":"hostname.example","app":"default-app","lvl":"DEBUG","msg":{"obj":12,"prop":false,"items":[1,2,3,4]}}
3{"ts":"2023-09-12T11:58:11+02:00","src":"hostname.example","app":"default-app","lvl":"ERROR","msg":"Erreur !!"}
4{"ts":"2023-09-12T12:58:11+02:00","src":"hostname.example","app":"default-app","lvl":"INFO","msg":"FIN"}

Une ligne correspond à une chaine json. à l'intérieur du json les champs suivants sont obligatoires :

  • ts = horodatage au format ISO 8601 (date + heure locale + offset du fuseau horaire)
  • src = hostname de la machine productrice du log
  • app = identification de l'application
  • lvl = niveau de sévérité : SUCCESS|INFO|WARNING|ERROR|DEBUG
  • msg = le message non structuré (dans le sens non indexable), qui peut être une chaîne de caractère, un type scalaire, un tableau ou objet json

Pour parser l'ensemble du fichier avec jq on utilise --slurp qui empaquête le ndjson dans un tableau json qu'il peut traiter / indenter / coloriser :

 1$ jq --slurp . log.ndjson
 2[
 3  {
 4    "ts": "2023-09-12T10:58:11+02:00",
 5    "src": "hostname.example",
 6    "app": "default-app",
 7    "lvl": "INFO",
 8    "msg": "DEBUT"
 9  },
10  {
11    "ts": 0
12  },
13  {
14    "sss": 12
15  }
16]

Si on veut filtrer une clé, par exemple remonter uniquement les erreurs

 1$ jq --slurp 'map(select(.lvl == "ERROR"))' log.ndjson
 2[
 3  {
 4    "ts": "2023-09-12T11:58:11+02:00",
 5    "src": "hostname.example",
 6    "app": "default-app",
 7    "lvl": "ERROR",
 8    "msg": "Erreur !!"
 9  }
10]

Ou un filtre sur une date

 1$ jq --arg tsStart '2023-09-12T11:00:00' --arg tsEnd '2023-09-12T12:00:00' --slurp 'map(select(.ts | . >= $tsStart and . <= $tsEnd))' log.ndjson
 2[
 3  {
 4    "ts": "2023-09-12T11:58:11+02:00",
 5    "src": "hostname.example",
 6    "app": "default-app",
 7    "lvl": "ERROR",
 8    "msg": "Erreur !!"
 9  }
10]
comments powered by Disqus