Conseils et dépannage pour l'écriture d'analyseurs
Ce document décrit les problèmes que vous pouvez rencontrer lorsque vous écrivez du code d'analyseur.
Lorsque vous écrivez le code de l'analyseur, vous pouvez rencontrer des erreurs si les instructions d'analyse ne fonctionnent pas comme prévu. Voici les situations qui peuvent générer des erreurs :
- Échec d'un modèle
Grok
- Échec d'une opération
rename
oureplace
- Erreurs de syntaxe dans le code de l'analyseur
Pratiques courantes d'utilisation du code d'analyse
Les sections suivantes décrivent les bonnes pratiques, les conseils et les solutions pour vous aider à résoudre les problèmes.
Évitez d'utiliser des points ou des traits d'union dans les noms de variables
L'utilisation de traits d'union et de points dans les noms de variables peut entraîner un comportement inattendu, souvent lors de l'exécution d'opérations merge
pour stocker des valeurs dans des champs UDM. Vous pouvez également rencontrer des problèmes d'analyse intermittents.
Par exemple, n'utilisez pas les noms de variables suivants :
my.variable.result
my-variable-result
Utilisez plutôt le nom de variable suivant: my_variable_result
.
N'utilisez pas de termes ayant une signification particulière comme nom de variable
Certains mots, comme event
et timestamp
, peuvent avoir une signification particulière dans l'analyseur
du code source.
La chaîne event
est souvent utilisée pour représenter un seul enregistrement UDM et est utilisée dans l'instruction @output
. Si un message de journal inclut un champ appelé event
, ou si vous définissez une variable intermédiaire appelée event
et que le code de l'analyseur utilise le mot event
dans l'instruction @output
, un message d'erreur concernant un conflit de nom s'affiche.
Renommez la variable intermédiaire ou utilisez le terme event1
comme préfixe dans les noms de champs UDM et dans l'instruction @output
.
Le mot timestamp
représente le code temporel créé du journal brut d'origine. Une valeur définie dans cette variable intermédiaire est enregistrée dans le champ UDM metadata.event_timestamp
. Le terme @timestamp
représente la date
et l'heure à laquelle le journal brut a été analysé
pour créer un enregistrement UDM.
L'exemple suivant définit le champ UDM metadata.event_timestamp
sur la date
et l'heure à laquelle le journal
brut a été analysé.
# Save the log parse date and time to the timestamp variable
mutate {
rename => {
"@timestamp" => "timestamp"
}
}
L'exemple suivant définit le champ UDM metadata.event_timestamp
sur la date et l'heure extraites du journal brut d'origine et stockées dans la variable intermédiaire when
.
# Save the event timestamp to timestamp variable
mutate {
rename => {
"when" => "timestamp"
}
}
N'utilisez pas les termes suivants comme variables :
- collectiontimestamp
- createtimestamp
- event
- filename
- message
- espace de noms
- output
- onerrorcount
- timestamp
- timezone
Stocker chaque valeur de données dans un champ UDM distinct
Ne stockez pas plusieurs champs dans un seul champ UDM en les concatenant avec un séparateur. En voici un exemple :
"principal.user.first_name" => "first:%{first_name},last:%{last_name}"
Stockez plutôt chaque valeur dans un champ UDM distinct.
"principal.user.first_name" => "%{first_name}"
"principal.user.last_name" => "%{last_name}"
Utiliser des espaces plutôt que des tabulations dans le code
N'utilisez pas d'onglets dans le code de l'analyseur. N'utilisez que des espaces et mettez en retrait deux espaces à la fois.
Ne pas effectuer plusieurs actions de fusion dans une même opération
Si vous fusionnez plusieurs champs dans une même opération, vous risquez d'obtenir des résultats incohérents. Placez plutôt les instructions merge
dans des opérations distinctes.
Par exemple, remplacez l'exemple suivant:
mutate {
merge => {
"security_result.category_details" => "category_details"
"security_result.category_details" => "super_category_details"
}
}
Par les lignes de code suivantes :
mutate {
merge => {
"security_result.category_details" => "category_details"
}
}
mutate {
merge => {
"security_result.category_details" => "super_category_details"
}
}
Choisir des expressions conditionnelles if
ou if else
Si la valeur conditionnelle que vous testez
ne peut avoir qu'une seule correspondance,
Utilisez ensuite l'instruction conditionnelle if else
. Cette approche est un peu plus
efficace. Toutefois, si la valeur testée peut correspondre à davantage
utilisez plusieurs instructions if
distinctes et organisez-les
du cas le plus générique
au cas le plus spécifique.
Choisissez un ensemble représentatif de fichiers journaux pour tester les modifications de l'analyseur
Une bonne pratique consiste à tester le code de l'analyseur à l'aide d'échantillons de journaux bruts avec une requête large dans différents formats. Cela vous permet de trouver des journaux uniques ou des cas particuliers que l'analyseur devra peut-être gérer.
Ajouter des commentaires descriptifs au code de l'analyseur
Ajoutez des commentaires au code de l'analyseur qui expliquent pourquoi l'instruction est importante, plutôt que ce qu'elle fait. Le commentaire aide toute personne responsable de la maintenance de l'analyseur de suivre le flux. En voici un exemple :
# only assign a Namespace if the source address is RFC 1918 or Loopback IP address
if [jsonPayload][id][orig_h] =~ /^(127(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(192\.168(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)|(172\.(?:1[6-9]|2\d|3[0-1])(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)/ {
mutate {
replace => {
"event1.idm.read_only_udm.principal.namespace" => "%{resource.labels.project_id}"
}
}
}
Initialiser les variables intermédiaires de manière précoce
Avant d'extraire les valeurs du journal brut d'origine, initialisez les requêtes intermédiaires qui serviront à stocker les valeurs de test.
Cela évite qu'une erreur soit renvoyée indiquant que la variable intermédiaire n'existe pas.
L'instruction suivante attribue la valeur de la variable product
au champ UDM metadata.product_name
.
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
Si la variable product
n'existe pas, vous obtenez l'erreur suivante:
"generic::invalid_argument: pipeline failed: filter mutate (4) failed: replace failure: field \"event1.idm.read_only_udm.metadata.product_name\": source field \"product\": field not set"
Vous pouvez ajouter une instruction on_error
pour détecter l'erreur. En voici un exemple :
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
on_error => "_error_does_not_exist"
}
L'exemple d'instruction précédent détecte correctement l'erreur d'analyse dans une variable intermédiaire booléenne, appelée _error_does_not_exist
. Il ne vous permet pas d'utiliser la variable product
dans une instruction conditionnelle, par exemple if
.
En voici un exemple :
if [product] != "" {
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
on_error => "_error_does_not_exist"
}
L'exemple précédent renvoie l'erreur suivante, car la clause conditionnelle if
n'est pas compatible avec les instructions on_error
:
"generic::invalid_argument: pipeline failed: filter conditional (4) failed: failed to evaluate expression: generic::invalid_argument: "product" not found in state data"
Pour résoudre ce problème, ajoutez un bloc d'instructions distinct qui initialise les variables intermédiaires avant d'exécuter les instructions du filtre d'extraction (json
, csv
, xml
, kv
ou grok
).
Consultez l'exemple suivant.
filter {
# Initialize intermediate variables for any field you will use for a conditional check
mutate {
replace => {
"timestamp" => ""
"does_not_exist" => ""
}
}
# load the logs fields from the message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
}
L'extrait de code de l'analyseur mis à jour gère les différents scénarios à l'aide d'une instruction conditionnelle pour vérifier si le champ existe. De plus, l'instruction on_error
gère les erreurs pouvant se produire.
Convertir SHA-256 en base64
L'exemple suivant extrait la valeur SHA-256, l'encode en base64, convertit les données encodées en chaîne hexadécimale, puis remplace des champs spécifiques par les valeurs extraites et traitées.
if [Sha256] != ""
{
base64
{
encoding => "RawStandard"
source => "Sha256"
target => "base64_sha256"
on_error => "base64_message_error"
}
mutate
{
convert =>
{
"base64_sha256" => "bytestohex"
}
on_error => "already_a_string"
}
mutate
{
replace =>
{
"event.idm.read_only_udm.network.tls.client.certificate.sha256" => "%{base64_sha256}"
"event.idm.read_only_udm.target.resource.name" => "%{Sha256}"
}
}
}
Gérer les erreurs dans les instructions d'analyse
Il n'est pas rare que les journaux entrants présentent un format ou contiennent des données mal formatées.
Vous pouvez créer l'analyseur pour gérer ces erreurs. Une bonne pratique consiste à ajouter
on_error
au filtre d'extraction, puis à
Testez la variable intermédiaire avant de passer au segment suivant de la logique de l'analyseur.
L'exemple suivant utilise le filtre d'extraction json
avec une instruction on_error
pour définir la variable booléenne _not_json
. Si _not_json
est défini sur
true
, cela signifie que l'entrée de journal entrante n'était pas dans un format JSON valide et que
L'entrée de journal n'a pas pu être analysée. Si la variable _not_json
est false
,
l'entrée de journal entrante était
dans un format JSON valide.
# load the incoming log from the default message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
Vous pouvez également vérifier si le format d'un champ est correct. L'exemple suivant vérifie si _not_json
est défini sur true
, ce qui indique que le journal n'était pas au format attendu.
# Test that the received log matches the expected format
if [_not_json] {
drop { tag => "TAG_MALFORMED_MESSAGE" }
} else {
# timestamp is always expected
if [timestamp] != "" {
# ...additional parser logic goes here …
} else {
# if the timestamp field does not exist, it's not a log source
drop { tag => "TAG_UNSUPPORTED" }
}
}
Cela garantit que l'analyse n'échoue pas si les journaux sont ingérés dans un format incorrect. pour le type de journal spécifié.
Utilisez le filtre drop
avec la variable tag
pour que la condition soit capturée dans le
Table des métriques d'ingestion dans BigQuery.
TAG_UNSUPPORTED
TAG_MALFORMED_ENCODING
TAG_MALFORMED_MESSAGE
TAG_NO_SECURITY_VALUE
Le filtre drop
empêche l'analyseur de traiter le journal brut, de normaliser les champs,
et la création d'un enregistrement UDM. Le journal brut d'origine est toujours ingéré dans Google Security Operations et peut être recherché à l'aide de la recherche de journaux bruts dans Google Security Operations.
La valeur transmise à la variable tag
est stockée dans la drop_reason_code
dans
Tableau des métriques d'ingestion. Vous pouvez exécuter une requête ad hoc sur la table, semblable à la suivante :
SELECT
log_type,
drop_reason_code,
COUNT(drop_reason_code) AS count
FROM `datalake.ingestion_metrics`
GROUP BY 1,2
ORDER BY 1 ASC
Résoudre les erreurs de validation
Lorsque vous créez un analyseur, vous pouvez rencontrer des erreurs liées à la validation. Par exemple, un champ obligatoire n'est pas défini dans l'enregistrement UDM. L'erreur peut se présenter comme suit :
Error: generic::unknown: invalid event 0: LOG_PARSING_GENERATED_INVALID_EVENT: "generic::invalid_argument: udm validation failed: target field is not set"
Le code d'analyse s'exécute correctement, mais pas l'enregistrement UDM généré.
incluez tous les champs UDM obligatoires tels que définis par la valeur metadata.event_type
. La
Voici d'autres exemples susceptibles de provoquer cette erreur:
- Si
metadata.event_type
estUSER_LOGIN
et que le champ UDMtarget.user value
n'est pas défini. - Si
metadata.event_type
estNETWORK_CONNECTION
et quetarget.hostname
Le champ "UDM" n'est pas défini.
Pour en savoir plus sur le champ UDM metadata.event_type
et les champs obligatoires, consultez le guide d'utilisation de la gestion des identités et des droits d'accès.
Pour résoudre ce type d'erreur, vous pouvez commencer par définir des valeurs statiques sur UDM . Après avoir défini tous les champs UDM nécessaires, examinez le journal brut d'origine pour identifier les champs à analyser et à enregistrer dans l'enregistrement UDM. Si le journal brut d'origine ne contiennent certains champs, vous devrez peut-être définir des valeurs par défaut.
Voici un exemple de modèle spécifique à un type d'événement USER_LOGIN
, qui
illustre bien cette approche.
Notez les points suivants:
- Le modèle initialise les variables intermédiaires et définit chacune d'elles sur une chaîne statique.
- Le code sous la section Field Assignment (Attribution de champ) définit les valeurs des variables intermédiaires sur les champs UDM.
Vous pouvez développer ce code en ajoutant des variables intermédiaires et des champs UDM supplémentaires. Une fois que vous avez identifié tous les champs UDM à renseigner, procédez comme suit :
Dans la section Configuration d'entrée, ajoutez du code qui extrait des champs du journal brut d'origine et définit les valeurs sur les variables intermédiaires.
Dans la section Date Extract, ajoutez le code qui extrait l'horodatage de l'événement. du journal brut d'origine, le transforme et le définit sur la variable intermédiaire.
Si nécessaire, remplacez l'ensemble de valeurs initialisées dans chaque variable intermédiaire par une chaîne vide.
filter {
mutate {
replace => {
# UDM > Metadata
"metadata_event_timestamp" => ""
"metadata_vendor_name" => "Example"
"metadata_product_name" => "Example SSO"
"metadata_product_version" => "1.0"
"metadata_product_event_type" => "login"
"metadata_product_log_id" => "12345678"
"metadata_description" => "A user logged in."
"metadata_event_type" => "USER_LOGIN"
# UDM > Principal
"principal_ip" => "192.168.2.10"
# UDM > Target
"target_application" => "Example Connect"
"target_user_user_display_name" => "Mary Smith"
"target_user_userid" => "mary@example.com"
# UDM > Extensions
"auth_type" => "SSO"
"auth_mechanism" => "USERNAME_PASSWORD"
# UDM > Security Results
"securityResult_action" => "ALLOW"
"security_result.severity" => "LOW"
}
}
# ------------ Input Configuration --------------
# Extract values from the message using one of the extraction filters: json, kv, grok
# ------------ Date Extract --------------
# If the date {} function is not used, the default is the normalization process time
# ------------ Field Assignment --------------
# UDM Metadata
mutate {
replace => {
"event1.idm.read_only_udm.metadata.vendor_name" => "%{metadata_vendor_name}"
"event1.idm.read_only_udm.metadata.product_name" => "%{metadata_product_name}"
"event1.idm.read_only_udm.metadata.product_version" => "%{metadata_product_version}"
"event1.idm.read_only_udm.metadata.product_event_type" => "%{metadata_product_event_type}"
"event1.idm.read_only_udm.metadata.product_log_id" => "%{metadata_product_log_id}"
"event1.idm.read_only_udm.metadata.description" => "%{metadata_description}"
"event1.idm.read_only_udm.metadata.event_type" => "%{metadata_event_type}"
}
}
# Set the UDM > auth fields
mutate {
replace => {
"event1.idm.read_only_udm.extensions.auth.type" => "%{auth_type}"
}
merge => {
"event1.idm.read_only_udm.extensions.auth.mechanism" => "auth_mechanism"
}
}
# Set the UDM > principal fields
mutate {
merge => {
"event1.idm.read_only_udm.principal.ip" => "principal_ip"
}
}
# Set the UDM > target fields
mutate {
replace => {
"event1.idm.read_only_udm.target.user.userid" => "%{target_user_userid}"
"event1.idm.read_only_udm.target.user.user_display_name" => "%{target_user_user_display_name}"
"event1.idm.read_only_udm.target.application" => "%{target_application}"
}
}
# Set the UDM > security_results fields
mutate {
merge => {
"security_result.action" => "securityResult_action"
}
}
# Set the security result
mutate {
merge => {
"event1.idm.read_only_udm.security_result" => "security_result"
}
}
# ------------ Output the event --------------
mutate {
merge => {
"@output" => "event1"
}
}
}
Analyser du texte non structuré à l'aide d'une fonction Grok
Lorsque vous utilisez une fonction Grok pour extraire des valeurs d'un texte non structuré, vous pouvez utiliser des modèles Grok prédéfinis et des instructions d'expression régulière. Motifs Grok
facilitent la lecture du code. Si l'expression régulière n'inclut pas de raccourci
caractères (\w
ou \s
, par exemple), vous pouvez copier et coller l'instruction directement
dans le code de l'analyseur.
Étant donné que les modèles Grok constituent une couche d'abstraction supplémentaire dans l'instruction, ils peuvent rendre le dépannage plus complexe lorsque vous rencontrez une erreur. Voici un exemple : Fonction Grok contenant à la fois des modèles Grok prédéfinis et des expressions régulières.
grok {
match => {
"message" => [
"%{NUMBER:when}\\s+\\d+\\s%{SYSLOGHOST:srcip} %{WORD:action}\\/%{NUMBER:returnCode} %{NUMBER:size} %{WORD:method} (?P<url>\\S+) (?P<username>.*?) %{WORD}\\/(?P<tgtip>\\S+).*"
]
}
}
Une instruction d'extraction sans modèles Grok peut être plus performante. Par exemple, l'exemple suivant nécessite moins de la moitié des étapes de traitement pour effectuer la mise en correspondance. Il s'agit d'un point important à prendre en compte pour une source de journaux potentiellement volumineuse.
Comprendre les différences entre les expressions régulières RE2 et PCRE
Les analyseurs Google Security Operations utilisent RE2 comme moteur d'expressions régulières. Si vous connaissez la syntaxe PCRE, vous remarquerez peut-être des différences. Voici un exemple:
Voici une instruction PCRE : (?<_custom_field>\w+)\s
Voici une instruction RE2 pour le code d'analyseur: (?P<_custom_field>\\w+)\\s
Veillez à échapper les caractères d'échappement.
Google Security Operations stocke les données de journaux brutes entrantes dans un format encodé au format JSON. Cela permet de s'assurer que les chaînes de caractères qui semblent être un raccourci d'expression régulière sont interprétées comme la chaîne littérale. Par exemple, \t
est interprété comme
plutôt qu'un caractère de tabulation.
L'exemple suivant est un journal brut d'origine et le journal au format JSON encodé.
Notez que le caractère d'échappement est ajouté devant chaque barre oblique inverse.
autour du terme entry
.
Voici le journal brut d'origine :
field=\entry\
Voici le journal converti au format encodé JSON :
field=\\entry\\
Lorsque vous utilisez une expression régulière dans le code de l'analyseur, vous devez ajouter des caractères d'échappement supplémentaires si vous souhaitez n'extraire que la valeur. Pour faire correspondre une barre oblique inverse dans le journal brut d'origine, utilisez quatre barres obliques inverses dans l'instruction d'extraction.
Voici une expression régulière pour le code de l'analyseur :
^field=\\\\(?P<_value>.*)\\\\$
Voici le résultat généré. Le groupe nommé _value
stocke le terme entry
:
"_value": "entry"
Lorsque vous déplacez une instruction d'expression régulière standard dans le code de l'analyseur, échappez les caractères abrégés d'expression régulière dans l'instruction d'extraction.
Par exemple, remplacez \s
par \\s
.
Ne modifiez pas les caractères spéciaux des expressions régulières en cas d'échappement double dans la partie
d'extraction. Par exemple, \\
reste inchangé en tant que \\
.
Voici une expression régulière standard:
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
L'expression régulière suivante a été modifiée pour fonctionner dans le code de l'analyseur.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
Le tableau suivant récapitule les cas où une expression régulière standard doit inclure des caractères d'échappement supplémentaires avant d'être incluse dans le code de l'analyseur.
Expression régulière | Expression régulière modifiée pour le code de l'analyseur | Description de la modification |
---|---|---|
\s |
\\s |
Les caractères abrégés doivent être échappés. |
\. |
\\. |
Les caractères réservés doivent être échappés. |
\\" |
\\\" |
Les caractères réservés doivent être échappés. |
\] |
\\] |
Les caractères réservés doivent être échappés. |
\| |
\\| |
Les caractères réservés doivent être échappés. |
[^\\]+ |
[^\\\\]+ |
Les caractères spéciaux d'un groupe de classes de caractères doivent être échappé. |
\\\\ |
\\\\ |
Les caractères spéciaux en dehors d'un groupe de classe de caractères ou les caractères abrégés ne nécessitent pas d'échappement supplémentaire. |
Les expressions régulières doivent inclure un groupe de capture nommé
Une expression régulière, telle que "^.*$"
, est une syntaxe RE2 valide. Toutefois, dans le code de l'analyseur, il échoue avec l'erreur suivante :
"ParseLogEntry failed: pipeline failed: filter grok (0) failed: failed to parse data with all match
patterns"
Vous devez ajouter un groupe de capture valide à l'expression. Si vous utilisez des modèles Grok, ils incluent un groupe de capture nommé par défaut. Si vous utilisez des d'expression, veillez à inclure un groupe nommé.
Voici un exemple d'expression régulière dans le code de l'analyseur :
"^(?P<_catchall>.*$)"
Voici le résultat, qui montre le texte attribué au groupe nommé _catchall
.
"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."
Utilisez un groupe nommé "catchall" pour commencer à créer l'expression
Lorsque vous créez une instruction d'extraction, commencez par une expression qui intercepte plus que vous ne le souhaitez. Développez ensuite l'expression un champ à la fois.
L'exemple suivant commence par utiliser un groupe nommé (_catchall
) qui correspond
l'intégralité du message. Il construit ensuite l'expression par étapes en faisant correspondre des parties supplémentaires du texte. À chaque étape, le groupe nommé _catchall
contient moins de texte d'origine. Continuez et itérez une étape à la fois pour faire correspondre le message jusqu'à ce que vous n'ayez plus besoin du groupe nommé _catchall
.
Étape | Expression régulière dans le code de l'analyseur | Sortie du groupe de capture nommé _catchall |
---|---|---|
1 | "^(?P<_catchall>.*$)" |
User \"BOB\" logged on to workstation \"DESKTOP-01\". |
2 | ^User\s\\\"(?P<_catchall>.*$) |
BOB\" logged on to workstation \"DESKTOP-01\". |
3 | ^User\s\\\"(?P<_user>.*?)\\\"\s(?P<_catchall>.*$) |
logged on to workstation \"DESKTOP-01\". |
Continuez jusqu'à ce que l'expression corresponde à toute la chaîne de texte. |
Échapper les caractères abrégés dans l'expression régulière
N'oubliez pas d'échapper les caractères abrégés d'expression régulière lorsque vous utilisez l'expression dans le code de l'analyseur. Voici un exemple de chaîne de texte et le
Expression régulière standard qui extrait le premier mot, This
.
This is a sample log.
L'expression régulière standard suivante extrait le premier mot, This
.
Toutefois, lorsque vous exécutez cette expression dans le code de l'analyseur, la lettre s
est manquante dans le résultat.
Expression régulière standard | Sortie du groupe de capture nommé _firstWord |
---|---|
"^(?P<_firstWord>[^\s]+)\s.*$" |
"_firstWord": "Thi", |
En effet, dans le code de l'analyseur, les expressions régulières nécessitent un échappement supplémentaire
ajouté aux caractères abrégées. Dans l'exemple précédent, \s
doit être remplacé par \\s
.
Expression régulière révisée pour le code de l'analyseur | Sortie du groupe de capture nommé _firstWord |
---|---|
"^(?P<_firstWord>[^\\s]+)\\s.*$" |
"_firstWord": "This", |
Cela ne s'applique qu'aux caractères abrégés, tels que \s
, \r
et \t
.
Les autres caractères, tels que ", ne doivent pas être échappés.
Exemple complet
Cette section décrit les règles précédentes sous la forme d'un exemple de bout en bout. Voici une chaîne de texte non structurée et l'expression régulière standard écrite pour l'analyser. Enfin, il inclut l'expression régulière modifiée qui fonctionne dans le code de l'analyseur.
Voici la chaîne de texte d'origine.
User "BOB" logged on to workstation "DESKTOP-01".
Voici une expression régulière RE2 standard qui analyse la chaîne de texte.
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
Cette expression extrait les champs suivants.
Groupe de correspondance | Position du caractère | Chaîne de texte |
---|---|---|
Correspondance complète | 0-53 | User \"BOB\" logged on to workstation \"DESKTOP-01\". |
Groupe "_user" | 7-10 | BOB |
Groupe 2. | 13-22 | logged on |
Groupe "_device" | 40-50 | DESKTOP-01 |
Il s'agit de l'expression modifiée. L'expression régulière RE2 standard a été modifiée pour fonctionner dans le code de l'analyseur.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$