Analyser des données de texte dans les journaux d’activité Azure Monitor

Certaines données de journal collectées par Azure Monitor incluront plusieurs informations au sein d'une même propriété. L’analyse de ces données dans plusieurs propriétés simplifie leur utilisation dans des requêtes. Un exemple courant est le journal personnalisé qui collecte une entrée de journal entière avec plusieurs valeurs dans une seule propriété. En créant des propriétés distinctes pour les différentes valeurs, vous pouvez faire des recherches et des agrégations sur chacune d’elles.

Cet article décrit différentes options pour l'analyse des données de journal dans Azure Monitor lorsque les données sont ingérées et lorsqu'elles sont extraites par une requête, en comparant les avantages de chacune.

Autorisations requises

  • Pour analyser les données au moment de la collecte, vous avez besoin d’autorisations Microsoft.Insights/dataCollectionRuleAssociations/*, telles que fournies par le rôle intégré Contributeur Log Analytics, par exemple.
  • Pour analyser des données au moment de la requête, vous avez besoin d’autorisations Microsoft.OperationalInsights/workspaces/query/*/read, telles que fournies par le rôle intégré Lecteur Log Analytics, par exemple.

Méthode d’analyse

Vous pouvez analyser les données au moment de l’ingestion lorsqu’elles sont collectées ou bien lors de la requête lorsque vous les analysez avec une requête. Chaque stratégie présente ses propres avantages.

Analyser les données au moment de la collection

Utilisez des transformations pour analyser les données au moment de la collecte et définir les colonnes auxquelles envoyer les données analysées.

Avantages :

  • Elle facilite l’interrogation des données collectées puisque vous n’avez pas besoin d’inclure des commandes d’analyse dans la requête.
  • Elle offre de meilleures performances de requête puisque que la requête n’a pas besoin d’effectuer l’analyse.

Inconvénients :

  • Elle doit être définie à l’avance. Elle ne peut pas inclure de données déjà collectées.
  • Une modification de la logique d’analyse s’applique uniquement aux nouvelles données.
  • Elle augmente le temps de latence pour la collecte des données.
  • Les erreurs peuvent être difficiles à traiter.

Analyser les données au moment de la requête

Lorsque vous analysez des données au moment de la requête, vous incluez une logique dans votre requête pour analyser les données dans plusieurs champs. La table elle-même n’est pas modifiée.

Avantages :

  • Elle s’applique à toutes les données, y compris celles déjà collectées.
  • Les modifications de la logique peuvent être immédiatement appliquées à toutes les données.
  • Les options d’analyse sont flexibles, incluant une logique prédéfinie pour les structures de données particulières.

Inconvénients :

  • Elle nécessite des requêtes plus complexes. L’utilisation de fonctions simulant une table permet d’atténuer cet inconvénient.
  • Elle nécessite de répliquer une logique d’analyse dans plusieurs requêtes. Elle peut partager une logique via des fonctions.
  • Elle peut créer une surcharge lorsque vous exécutez une logique complexe sur de très grands jeux d’enregistrement (comprenant des milliards d’enregistrements).

Analyser les données lors de la collecte

Pour plus d’informations sur l’analyse des données au fur et à mesure de leur collecte, consultez Structure de transformation dans Azure Monitor. Cette approche créée des propriétés personnalisées dans le tableau, pouvant être utilisées par les requêtes comme n’importe quelle autre propriété.

Analyser les données dans une requête à l’aide de modèles

Lorsque les données que vous souhaitez analyser peuvent être identifiées par un modèle répété sur plusieurs enregistrements, vous pouvez utiliser différents opérateurs du langage de requête Kusto pour extraire la donnée spécifique dans une ou plusieurs nouvelles propriétés.

Modèles de texte simples

Utilisez l’opérateur d’analyse dans votre requête pour créer une ou plusieurs propriétés personnalisées pouvant être extraites à partir d’une expression de chaîne. Vous spécifiez le modèle à identifier et le nom des propriétés à créer. Cette approche est utile pour les données comprenant des chaînes de clé-valeur avec une forme similaire à key=value.

Imaginons un journal personnalisé avec des données au format suivant :

Time=2018-03-10 01:34:36 Event Code=207 Status=Success Message=Client 05a26a97-272a-4bc9-8f64-269d154b0e39 connected
Time=2018-03-10 01:33:33 Event Code=208 Status=Warning Message=Client ec53d95c-1c88-41ae-8174-92104212de5d disconnected
Time=2018-03-10 01:35:44 Event Code=209 Status=Success Message=Transaction 10d65890-b003-48f8-9cfc-9c74b51189c8 succeeded
Time=2018-03-10 01:38:22 Event Code=302 Status=Error Message=Application could not connect to database
Time=2018-03-10 01:31:34 Event Code=303 Status=Error Message=Application lost connection to database

La requête suivante analyse ces données dans des propriétés individuelles. La ligne avec project est ajoutée afin de retourner uniquement les propriétés calculées et pas RawData, qui est la seule propriété qui contient l’entrée complète à partir du journal personnalisé.

MyCustomLog_CL
| parse RawData with * "Time=" EventTime " Event Code=" Code " Status=" Status " Message=" Message
| project EventTime, Code, Status, Message

Cet exemple découpe le nom d’utilisateur d’un UPN dans le AzureActivity tableau.

AzureActivity
| parse  Caller with UPNUserPart "@" * 
| where UPNUserPart != "" //Remove non UPN callers (apps, SPNs, etc)
| distinct UPNUserPart, Caller

Expressions régulières

Si vos données peuvent être identifiées avec une expression régulière, vous pouvez utiliser des fonctions utilisant des expressions régulières pour extraire les valeurs individuelles. L’exemple suivant utilise extract pour diviser le champ UPN à partir des enregistrements AzureActivity, puis retourne des utilisateurs distincts.

AzureActivity
| extend UPNUserPart = extract("([a-z.]*)@", 1, Caller) 
| distinct UPNUserPart, Caller

Pour permettre une analyse efficace à grande échelle, Azure Monitor utilise la version re2 des Expressions régulières, qui est similaire mais pas identique à d'autres variantes d'expressions régulières. Pour plus d’informations, consultez la syntaxe de l’expression re2.

Analyser des données délimitées dans une requête

Des données délimitées séparent les champs avec un caractère commun, comme une virgule dans un fichier CSV. Utilisez la fonction split pour analyser des données délimitées à l’aide d’un délimiteur que vous spécifiez. Vous pouvez utiliser cette approche avec l’opérateur extend pour retourner tous les champs dans les données ou pour spécifier des champs individuels à inclure dans la sortie.

Notes

Puisque split renvoie un objet dynamique, il est possible que les résultats doivent être explicitement castés en types de données comme une chaîne à utiliser dans les opérateurs et les filtres.

Imaginons un journal personnalisé avec des données au format CSV suivant :

2018-03-10 01:34:36, 207,Success,Client 05a26a97-272a-4bc9-8f64-269d154b0e39 connected
2018-03-10 01:33:33, 208,Warning,Client ec53d95c-1c88-41ae-8174-92104212de5d disconnected
2018-03-10 01:35:44, 209,Success,Transaction 10d65890-b003-48f8-9cfc-9c74b51189c8 succeeded
2018-03-10 01:38:22, 302,Error,Application could not connect to database
2018-03-10 01:31:34, 303,Error,Application lost connection to database

La requête suivante analyse ces données et les synthétise par deux des propriétés calculées. La première ligne fractionne la propriété RawData dans un groupe de chaînes. Chacune des lignes suivantes donne un nom aux propriétés individuelles et les ajoute à la sortie en utilisant des fonctions pour les convertir en type de données approprié.

MyCustomCSVLog_CL
| extend CSVFields  = split(RawData, ',')
| extend EventTime  = todatetime(CSVFields[0])
| extend Code       = toint(CSVFields[1]) 
| extend Status     = tostring(CSVFields[2]) 
| extend Message    = tostring(CSVFields[3]) 
| where getyear(EventTime) == 2018
| summarize count() by Status,Code

Analyser des structures prédéfinies dans une requête

Si vos données sont formatées dans une structure connue, vous pourrez peut-être utiliser l'une des fonctions du langage de requête Kusto pour analyser des structures prédéfinies :

L’exemple de requête suivant analyse le champ Properties de la table AzureActivity, structurée en JSON. Il enregistre les résultats dans une propriété dynamique appelée parsedProp, qui inclut la valeur nommée individuellement en JSON. Ces valeurs sont utilisées pour filtrer et résumer les résultats de requête.

AzureActivity
| extend parsedProp = parse_json(Properties) 
| where parsedProp.isComplianceCheck == "True" 
| summarize count() by ResourceGroup, tostring(parsedProp.tags.businessowner)

Ces fonctions d’analyse peuvent être gourmandes en processeur. Utilisez-les uniquement lorsque votre requête utilise plusieurs propriétés des données mises en forme. Autrement, le traitement simple des critères spéciaux est plus rapide.

L’exemple suivant montre la répartition du TGT Preauth type de contrôleur de domaine. Ce type n’existe seulement que dans le EventData champ, qui est une chaîne XML. Aucune autre donnée de ce champ n’est nécessaire. Dans ce cas, parse est utilisé pour extraire les données indispensables.

SecurityEvent
| where EventID == 4768
| parse EventData with * 'PreAuthType">' PreAuthType '</Data>' * 
| summarize count() by PreAuthType

Utiliser une fonction pour simuler un tableau

Vous pourriez avoir plusieurs requêtes effectuant la même analyse d’un tableau particulier. Dans ce cas, créez une fonction qui retourne les données analysées au lieu de répliquer la logique d’analyse dans chaque requête. Vous pouvez ensuite utiliser l’alias de fonction à la place de la table d’origine dans les autres requêtes.

Prenons l’exemple du précédent journal personnalisé délimité par des virgules. Pour pouvoir utiliser les données analysées dans plusieurs requêtes, créez une fonction à l’aide de la requête suivante et enregistrez-la avec l’alias MyCustomCSVLog.

MyCustomCSVLog_CL
| extend CSVFields = split(RawData, ',')
| extend DateTime  = tostring(CSVFields[0])
| extend Code      = toint(CSVFields[1]) 
| extend Status    = tostring(CSVFields[2]) 
| extend Message   = tostring(CSVFields[3]) 

Vous pouvez maintenant utiliser l’alias MyCustomCSVLog à la place du nom du tableau actuel dans les requêtes, comme l’exemple suivant :

MyCustomCSVLog
| summarize count() by Status,Code

Étapes suivantes

Découvrez les requêtes dans les journaux pour analyser les données collectées à partir de sources de données et de solutions.