vendredi 27 octobre 2017

Grok pattern conditionnel check

Problème

Lorsque l'ont veut appliquer un pattern grok sur une chaine envoyée par filebeat par exemple, il arrive que certains champs qui doivent respecter un pattern donné soit vide ce qui se traduit coté grok par un pattern qui ne correspond pas et donc par un parsing qui n'est pas envoyé correctement à elastic search. 

Exemple

Soit la chaine suivante : 
[27/Oct/2017:15:38:48 +0200] 127.0.0.1 - 200 80 212 GET /show HTTP/1.1

Et le pattern grock suivant : 
\[%{MONTHDAY}[./-]%{WORD}[./-]%{YEAR}[:]%{TIME}%{SPACE}[+]%{INT}\]%{SPACE}%{IP:[parameters][remoteip]}%{SPACE}%{USER:[parameters][user]}%{SPACE}%{INT:[parameters][httpcode]}%{SPACE}%{INT:[parameters][localport]}%{SPACE}%{INT:[parameters][processtime]}%{SPACE}%{GREEDYDATA:[parameters][requestfistline]}

Le résultat attendu :

{
  "MONTHDAY": [
    [
      "27"
    ]
  ],
  "WORD": [
    [
      "Oct"
    ]
  ],
  "YEAR": [
    [
      "2017"
    ]
  ],
  "TIME": [
    [
      "15:38:48"
    ]
  ],
  "HOUR": [
    [
      "15"
    ]
  ],
  "MINUTE": [
    [
      "38"
    ]
  ],
  "SECOND": [
    [
      "48"
    ]
  ],
  "SPACE": [
    [
      " ",
      " ",
      " ",
      " ",
      " ",
      " ",
      " "
    ]
  ],
  "INT": [
    [
      "0200"
    ]
  ],
  "[parameters][remoteip]": [
    [
      "127.0.0.1"
    ]
  ],
  "IPV6": [
    [
      null
    ]
  ],
  "IPV4": [
    [
      "127.0.0.1"
    ]
  ],
  "[parameters][user]": [
    [
      "-"
    ]
  ],
  "USERNAME": [
    [
      "-"
    ]
  ],
  "[parameters][httpcode]": [
    [
      "200"
    ]
  ],
  "[parameters][localport]": [
    [
      "80"
    ]
  ],
  "[parameters][processtime]": [
    [
      "212"
    ]
  ],
  "[parameters][requestfistline]": [
    [
      "GET /show HTTP/1.1"
    ]
  ]
}

Si dans la chaîne récupérée l'ip n’apparaît plus alors le pattern ne sera pas correspondant:
[27/Oct/2017:15:38:48 +0200]  - 200 80 212 GET /show HTTP/1.1

Solution

Utiliser le terme conditionnel pour la vérification du pattern.
Cela se traduit par l'utilisation de (?:le terme a mettre en conditionnel |).

Exemple : 

\[%{MONTHDAY}[./-]%{WORD}[./-]%{YEAR}[:]%{TIME}%{SPACE}[+]%{INT}\]%{SPACE}(?:%{IP:[parameters][remoteip]}|)%{SPACE}%{USER:[parameters][user]}%{SPACE}%{INT:[parameters][httpcode]}%{SPACE}%{INT:[parameters][localport]}%{SPACE}%{INT:[parameters][processtime]}%{SPACE}%{GREEDYDATA:[parameters][requestfistline]}

Maintenant le pattern est bien correspondant et la chaîne traitée correctement.