Datadog effectue automatiquement le parsing de vos logs au format JSON. Pour les autres formats, Datadog vous permet d’enrichir vos logs à l’aide du parser Grok. Comparée à l’utilisation exclusive d’expressions régulières, la syntaxe Grok simplifie le parsing des logs. Le parser Grok vous permet d’extraire des attributs à partir de messages texte semi-structurés.
Grok propose des patterns réutilisables pour parser des entiers, des adresses IP, des hostnames, etc.
Vous pouvez rédiger des règles de parsing à l’aide de la syntaxe %{MATCHER:EXTRACT:FILTER}
:
Matcher : une règle (éventuellement une référence à la règle d’un autre token) qui décrit la valeur attendue (number, word, notSpace, etc.).
Extract (facultatif) : un identifiant représentant la destination d’enregistrement pour le morceau de texte correspondant au Matcher.
Filter (facultatif) : un post-processeur de la correspondance permettant de la transformer.
Exemple d’un log non structuré standard :
john connected on 11/08/2017
Avec la règle de parsing suivante :
MyParsingRule %{word:user} connected on %{date("MM/dd/yyyy"):connect_date}
Une fois le traitement terminé, le log structuré suivant est généré :
Remarque :
_
et .
. Ils doivent commencer par un caractère alphanumérique.Voici la liste de tous les matchers et de tous les filtres implémentés en natif par Datadog :
Pattern | Utilisation |
date("pattern"[, "timezoneId"[, "localeId"]]) | Renvoie une date correspondant au pattern et aux valeurs parsées pour produire un timestamp Unix. Consulter les exemples de Matcher de date. |
regex("pattern") | Renvoie un regex. Consulter les exemples de Matcher de regex. |
data | Renvoie n’importe quelle chaîne, espaces et sauts de ligne inclus. Équivaut à .* . |
notSpace | Renvoie n’importe quelle chaîne jusqu’à la prochaine espace. |
boolean("patternTrue", "patternFalse") | Renvoie et parse une valeur booléenne qui définit de façon facultative les patterns true et false (par défaut, true et false en ignorant la casse). |
numberStr | Renvoie un nombre flottant et le parse en tant que chaîne. |
number | Renvoie un nombre flottant et le parse en tant que nombre à double précision. |
numberExtStr | Renvoie un nombre flottant (avec prise en charge de la notation scientifique) et le parse en tant que chaîne. |
numberExt | Renvoie un nombre flottant (avec prise en charge de la notation scientifique) et le parse en tant que nombre à double précision. |
integerStr | Renvoie un nombre entier et le parse en tant que chaîne. |
integer | Renvoie un nombre entier et le parse en tant que nombre entier. |
integerExtStr | Renvoie un nombre entier (avec prise en charge de la notation scientifique) et le parse en tant que chaîne. |
integerExt | Renvoie un nombre entier (avec prise en charge de la notation scientifique) et le parse en tant que nombre entier. |
word | Renvoie les caractères a à z, A à Z, 0 à 9, y compris le caractère _ (underscore). |
doubleQuotedString | Renvoie une chaîne entre guillemets. |
singleQuotedString | Renvoie une chaîne entre apostrophes. |
quotedString | Renvoie une chaîne entre guillemets ou entre apostrophes. |
uuid | Renvoie un UUID. |
mac | Renvoie une adresse MAC. |
ipv4 | Renvoie une adresse IPV4. |
ipv6 | Renvoie une adresse IPV6. |
ip | Renvoie une adresse IP (v4 ou v6). |
hostname | Renvoie un hostname. |
ipOrHost | Renvoie un hostname ou une IP. |
port | Renvoie un numéro de port. |
Pattern | Utilisation |
number | Parse une correspondance en tant que nombre à double précision. |
integer | Parse une correspondance en tant que nombre entier. |
boolean | Parse les chaînes ‘true’ et ‘false’ en tant que valeurs booléennes ignorant la casse. |
nullIf("value") | Renvoie une valeur null si la correspondance est identique à la valeur fournie. |
json | Parse du JSON correctement formaté. |
rubyhash | Parse un hash Ruby correctement formaté (par exemple, {nom=> "John", "poste" => {"entreprise" => "Grosse entreprise", "titre" => "Directeur technique"}} ). |
useragent([decodeuricomponent:true/false]) | Parse un user agent et renvoie un objet JSON qui contient l’appareil, le système d’exploitation et le navigateur représenté par l’Agent. En savoir plus sur le processeur d’user-agent. |
querystring | Extrait toutes les paires key/value d’une chaîne de requête URL correspondante (par exemple, ?productId=superproduct&promotionCode=superpromo ). |
decodeuricomponent | Ce filtre décode les composants d’un URI. Par exemple, il permet de transformer %2Fservice%2Ftest en /service/test . |
lowercase | Renvoie la chaîne en minuscules. |
uppercase | Renvoie la chaîne en majuscules. |
keyvalue([separatorStr[, characterWhiteList[, quotingStr[, delimiter]]]]) | Extrait une expression clé/valeur et renvoie un objet JSON. Consulter les exemples de filtres clé/valeur. |
xml | Parse du XML correctement formaté. Consulter les exemples de filtres XML. |
csv(headers[, separator[, quotingcharacter]]) | Parse des lignes CSV ou TSV correctement formatées. Consulter les exemples de filtres CSV. |
scale(facteur) | Multiplie la valeur numérique attendue par le coefficient spécifié. |
array([[openCloseStr, ] separator][, subRuleOrFilter) | Parse une séquence de tokens et la renvoie en tant que tableau. |
url | Parse une URL et renvoie tous les membres tokenisés (domaine, paramètres de requête, port, etc.) dans un objet JSON. En savoir plus sur le parsing d’URL. |
En bas de vos carrés de processeur Grok, vous trouverez une section Advanced Settings :
Utilisez le champ Extract from pour appliquer votre processeur Grok sur un attribut texte donné plutôt que sur l’attribut message
par défaut.
Imaginez par exemple un log contenant un attribut command.line
devant être parsé en tant que key/value. Le parsing de ce log peut se faire comme suit :
Utilisez le champ Helper Rules afin de définir les tokens pour vos règles de parsing. Les règles d’auxiliaires vous aident à factoriser les patterns Grok dans vos règles de parsing, ce qui est utile lorsque plusieurs règles d’un même parser Grok utilisent les mêmes tokens.
Exemple d’un log non structuré standard :
john id:12345 connected on 11/08/2017 on server XYZ in production
Utilisez la règle de parsing suivante :
MyParsingRule %{user} %{connection} %{server}
Avec les auxiliaires suivants :
user %{word:user.name} id:%{integer:user.id}
connection connected on %{date("MM/dd/yyyy"):connect_date}
server on server %{notSpace:server.name} in %{notSpace:server.env}
Voici des exemples d’utilisation des parsers :
Le filtre key/value correspond à keyvalue([separatorStr[, characterWhiteList[, quotingStr[, delimiter]]]])
, où :
separatorStr
définit le séparateur entre la clé et les valeurs. Par défaut, =
.characterWhiteList
définit des caractères supplémentaires non échappés en plus de la valeur par défaut \\w.\\-_@
. Uniquement utilisé pour les valeurs sans guillemets (par exemple, key=@valueStr
).quotingStr
définit des guillemets, ce qui remplace la détection de guillemets par défaut : <>
, ""
, ''
.delimiter
définit le séparateur entre les différentes paires key/value (par exemple, |
est le délimiteur dans key1=value1|key2=value2
). Par défaut,
(espace normale), ,
et ;
.Utilisez des filtres tels que keyvalue pour mapper plus facilement des chaînes à des attributs au format keyvalue ou logfmt :
Log :
user=john connect_date=11/08/2017 id=123 action=click
Règle :
rule %{data::keyvalue}
Vous n’avez pas besoin de spécifier le nom de vos paramètres, car ils sont déjà contenus dans le log.
Si vous ajoutez un attribut d’extraction my_attribute
dans votre pattern de règles, vous obtenez :
Si le caractère =
n’est pas le séparateur par défaut entre votre clé et vos valeurs, ajoutez à votre règle de parsing un paramètre avec un séparateur.
Log :
user: john connect_date: 11/08/2017 id: 123 action: click
Règle :
rule %{data::keyvalue(": ")}
Si les logs contiennent des caractères spéciaux dans une valeur d’attribut, tels que /
dans une URL, ajoutez-les à la liste blanche de la règle de parsing :
Log :
url=https://app.datadoghq.com/event/stream user=john
Règle :
rule %{data::keyvalue("=","/:")}
Autres exemples :
Chaîne brute | Règle de parsing | Résultat |
---|---|---|
key=valueStr | %{data::keyvalue} | {“key”: “valueStr} |
key=<valueStr> | %{data::keyvalue} | {“key”: “valueStr”} |
“key”=“valueStr” | %{data::keyvalue} | {“key”: “valueStr”} |
key:valueStr | %{data::keyvalue(":")} | {“key”: “valueStr”} |
key:"/valueStr” | %{data::keyvalue(":", "/")} | {“key”: “/valueStr”} |
/key:/valueStr | %{data::keyvalue(":", "/")} | {"/key": “/valueStr”} |
key:={valueStr} | %{data::keyvalue(":=", "", "{}")} | {“key”: “valueStr”} |
key1=value1|key2=value2 | %{data::keyvalue("=", "", "", "|")} | {“key1”: “value1”, “key2”: “value2”} |
key1=“value1”|key2=“value2” | %{data::keyvalue("=", "", "", "|")} | {“key1”: “value1”, “key2”: “value2”} |
Exemple avec plusieurs QuotingString : lorsque plusieurs QuotingString sont définies, le comportement par défaut est ignoré, et seul le guillemet défini est autorisé.
Le filtre key/value met toujours en correspondance des entrées sans guillemet, peu importe la valeur de quotingStr
. Lorsque des guillemets sont utilisés, le paramètre characterWhiteList
est ignoré, puisque tout le contenu entre les guillemets est extrait.
Log :
key1:=valueStr key2:=</valueStr2> key3:="valueStr3"
Règle :
rule %{data::keyvalue(":=","","<>")}
Résultat :
{"key1": "valueStr", "key2": "/valueStr2"}
Remarques :
key=
) ou null
(key=null
) ne sont pas affichées dans la sortie JSON.data
et que ce filtre n’est pas mis en correspondance, un JSON vide {}
est renvoyé (par exemple, entrée : key:=valueStr
, règle de parsing : rule_test %{data::keyvalue("=")}
, sortie : {}
).""
en tant que quotingStr
, la configuration par défaut des guillemets est conservée.Le matcher de date convertit votre timestamp au format EPOCH (unité de mesure : millisecondes).
Chaîne brute | Règle de parsing | Résultat |
---|---|---|
14:20:15 | %{date("HH:mm:ss"):date} | {“date”: 51615000} |
02:20:15 PM | %{date("hh:mm:ss a"):date} | {“date”: 51615000} |
11/10/2014 | %{date("dd/MM/yyyy"):date} | {“date”: 1412978400000} |
Thu Jun 16 08:29:03 2016 | %{date("EEE MMM dd HH:mm:ss yyyy"):date} | {“date”: 1466065743000} |
Tue Nov 1 08:29:03 2016 | %{date("EEE MMM d HH:mm:ss yyyy"):date} | {“date”: 1466065743000} |
06/Mar/2013:01:36:30 +0900 | %{date("dd/MMM/yyyy:HH:mm:ss Z"):date} | {“date”: 1362501390000} |
2016-11-29T16:21:36.431+0000 | %{date("yyyy-MM-dd'T'HH:mm:ss.SSSZ"):date} | {“date”: 1480436496431} |
2016-11-29T16:21:36.431+00:00 | %{date("yyyy-MM-dd'T'HH:mm:ss.SSSZZ"):date} | {“date”: 1480436496431} |
06/Feb/2009:12:14:14.655 | %{date("dd/MMM/yyyy:HH:mm:ss.SSS"):date} | {“date”: 1233922454655} |
2007-08-31 19:22:22.427 ADT | %{date("yyyy-MM-dd HH:mm:ss.SSS z"):date} | {“date”: 1188598942427} |
Thu Jun 16 08:29:03 20161 | %{date("EEE MMM dd HH:mm:ss yyyy","Europe/Paris"):date} | {“date”: 1466058543000} |
Thu Jun 16 08:29:03 20161 | %{date("EEE MMM dd HH:mm:ss yyyy","UTC+5"):date} | {“date”: 1466047743000} |
Thu Jun 16 08:29:03 20161 | %{date("EEE MMM dd HH:mm:ss yyyy","+3"):date} | {“date”: 1466054943000} |
1 Utilisez le paramètre timezone
si vous effectuez vos propres localisations et que vos timestamps ne sont pas au fuseau UTC.
Les formats de fuseaux horaires pris en charge sont les suivants :
GMT
, UTC
, UT
ou Z
+h
, +hh
, +hh:mm
, -hh:mm
, +hhmm
, -hhmm
, +hh:mm:ss
, -hh:mm:ss
, +hhmmss
ou -hhmmss
. La plage la plus étendue prise en charge est de +18:00 à -18:00 (inclus).UTC+
, UTC-
, GMT+
, GMT-
, UT+
ou UT-
. La plage la plus étendue prise en charge est de +18:00 à -18:00 (inclus).Remarque : le parsing d’une date ne définit pas sa valeur comme étant la date officielle du log. Pour cela, utilisez le remappeur de dates de log dans un processeur ultérieur.
Si vous avez des logs qui se présentent dans deux formats différents, avec un unique attribut comme seule différence, définissez une seule règle en utilisant une alternative avec (<REGEX_1>|<REGEX_2>)
. Cette règle équivaut à un OR booléen.
Log :
john connected on 11/08/2017
12345 connected on 11/08/2017
Règle : Notez que « id » est un nombre entier et non une chaîne.
MyParsingRule (%{integer:user.id}|%{word:user.firstname}) connected on %{date("MM/dd/yyyy"):connect_date}
Résultats :
Certains logs contiennent des valeurs qui n’apparaissent que de temps en temps. Dans ce cas, vous pouvez rendre l’extraction d’attributs facultative avec ()?
.
Log :
john 1234 connected on 11/08/2017
Règle :
MyParsingRule %{word:user.firstname} (%{integer:user.id} )?connected on %{date("MM/dd/yyyy"):connect_date}
Remarque : la règle ne fonctionnera pas si vous ajoutez une espace après le premier mot dans la section facultative.
Utilisez le filtre json
pour effectuer le parsing d’un objet JSON imbriqué après un préfixe en texte brut :
Log :
Sep 06 09:13:38 vagrant program[123]: server.1 {"method":"GET", "status_code":200, "url":"https://app.datadoghq.com/logs/pipelines", "duration":123456}
Règle :
parsing_rule %{date("MMM dd HH:mm:ss"):timestamp} %{word:vm} %{word:app}\[%{number:logger.thread_id}\]: %{notSpace:server} %{data::json}
Utilisez le matcher regex pour identifier une sous-chaîne de votre message de log.
Log :
john_1a2b3c4 connected on 11/08/2017
Règle :
MyParsingRule %{regex("[a-z]*"):user.firstname}_%{regex("[a-zA-Z0-9]*"):user.id} .*
Utilisez le matcher array
pour extraire une liste sous la forme d’un tableau dans un attribut unique.
Log :
Users [John, Oliver, Marc, Tom] have been added to the database
Règle :
myParsingRule Users %{data:users:array(“[]“,”,“)} have been added to the database
Log :
Users {John-Oliver-Marc-Tom} have been added to the database
Règle :
myParsingRule Users %{data:users:array("{}","-")} have been added to the database
Certains composants Kubernetes génèrent leurs logs au format glog
. Cet exemple est tiré du composant Kube Scheduler dans la bibliothèque de pipelines.
Exemple de ligne de log :
W0424 11:47:41.605188 1 authorization.go:47] Authorization is disabled
Règles de parsing :
kube_scheduler %{regex("\\w"):level}%{date("MMdd HH:mm:ss.SSSSSS"):timestamp}\s+%{number:logger.thread_id} %{notSpace:logger.name}:%{number:logger.lineno}\] %{data:msg}
JSON extrait :
{
"level": "W",
"timestamp": 1587728861605,
"logger": {
"thread_id": 1,
"name": "authorization.go"
},
"lineno": 47,
"msg": "Authorization is disabled"
}
Le parser de XML permet de transformer des messages au format XML en JSON.
Log :
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
</book>
Règle :
rule %{data::xml}
Résultat :
{
"book": {
"year": "2005",
"author": "J K. Rowling",
"category": "CHILDREN",
"title": {
"lang": "en",
"value": "Harry Potter"
}
}
}
Remarques :
value
est généré. Par exemple : <title lang="en">Harry Potter</title>
devient {"title": {"lang": "en", "value": "Harry Potter" } }
<bookstore><book>Harry Potter</book><book>Everyday Italian</book></bookstore>
devient { "bookstore": { "book": [ "Harry Potter", "Everyday Italian" ] } }
Utilisez le filtre CSV pour mapper plus facilement les chaînes de caractères aux attributs lorsqu’elles sont séparées par un caractère donné (,
par défaut).
Le filtre CSV correspond à csv(headers[, separator[, quotingcharacter]])
, où :
headers
définit le nom des clés séparées par ,
. Les noms des clés doivent commencer par un caractère alphabétique et peuvent contenir n’importe quel caractère alphanumérique en plus de _
.separator
définit le séparateur utilisé pour séparer les différentes valeurs. Seul un caractère est accepté. Valeur par défaut : ,
. Remarque : utilisez tab
pour représenter le caractère de tabulation.quotingcharacter
définit le caractère des guillemets. Seul un caractère est accepté. Valeur par défaut : "
Remarques :
""
représente "
.Log :
John,Doe,120,Jefferson St.,Riverside
Règle :
myParsingRule %{data:user:csv("first_name,name,st_nb,st_name,city")}
Résultat :
{
"user": {
"first_name": "John",
"name": "Doe",
"st_nb": 120,
"st_name": "Jefferson St.",
"city": "Riverside"
}
}
Autres exemples :
Chaîne brute | Règle de parsing | Résultat |
---|---|---|
John,Doe | %{data::csv("firstname,name")} | {“firstname”: “John”, “name”:“Doe”} |
"John ""Da Man""",Doe | %{data::csv("firstname,name")} | {“firstname”: “John "Da Man"”, “name”:“Doe”} |
'John ''Da Man''',Doe | %{data::csv("firstname,name",",","'")} | {“firstname”: “John ‘Da Man’”, “name”:“Doe”} |
John|Doe | %{data::csv("firstname,name","|")} | {“firstname”: “John”, “name”:“Doe”} |
value1,value2,value3 | %{data::csv("key1,key2")} | {“key1”: “value1”, “key2”:“value2”} |
value1,value2 | %{data::csv("key1,key2,key3")} | {“key1”: “value1”, “key2”:“value2”} |
value1,,value3 | %{data::csv("key1,key2,key3")} | {“key1”: “value1”, “key3”:“value3”} |
Documentation, liens et articles supplémentaires utiles:
Sur cette page