Suggerimenti e risoluzione dei problemi relativi alla scrittura dei parser
Questo documento descrive i problemi che potresti riscontrare quando scrivi il codice del parser.
Durante la scrittura del codice del parser, potresti riscontrare errori quando le istruzioni di analisi non funzionano come previsto. Le situazioni che potrebbero generare errori sono le seguenti:
- Una sequenza
Grok
non va a buon fine - Un'operazione
rename
oreplace
non va a buon fine - Errori di sintassi nel codice del parser
Pratiche comuni nel codice del parser
Le seguenti sezioni descrivono le best practice, i suggerimenti e le soluzioni per la risoluzione dei problemi.
Evita di utilizzare punti o trattini nei nomi delle variabili.
L'utilizzo di trattini e punti nei nomi delle variabili può causare comportamenti imprevisti,
spesso durante l'esecuzione di operazioni merge
per archiviare i valori nei campi UDM. Potresti anche riscontrare problemi di analisi intermittente.
Ad esempio, non utilizzare i seguenti nomi di variabili:
my.variable.result
my-variable-result
Utilizza invece il seguente nome di variabile: my_variable_result
.
Non utilizzare termini con un significato speciale nei nomi delle variabili
Determinate parole, come event
e timestamp
, possono avere un significato speciale nel codice del parser.
La stringa event
viene spesso utilizzata per rappresentare un singolo record UDM e nell'istruzione @output
. Se un messaggio di log include un campo denominato event
o
se definisci una variabile intermedia denominata event
e il
codice del parser utilizza la parola event
nell'istruzione @output
, riceverai un
messaggio di errore relativo a un conflitto di nomi.
Rinomina la variabile intermedia in un altro nome o utilizza il termine event1
come
prefisso nei nomi dei campi UDM e nell'istruzione @output
.
La parola timestamp
rappresenta il timestamp di creazione del log non elaborato originale. Un
valore impostato in questa variabile intermedia viene salvato nel
campo UDM metadata.event_timestamp
. Il termine @timestamp
rappresenta la data e l'ora in cui il log non elaborato è stato analizzato per creare un record UDM.
L'esempio seguente imposta il campo UDM metadata.event_timestamp
sulla data e sull'ora in cui il log non elaborato è stato analizzato.
# Save the log parse date and time to the timestamp variable
mutate {
rename => {
"@timestamp" => "timestamp"
}
}
L'esempio seguente imposta il campo UDM metadata.event_timestamp
sulla data e sull'ora estratti dal log non elaborato originale e archiviati nella variabile intermedia when
.
# Save the event timestamp to timestamp variable
mutate {
rename => {
"when" => "timestamp"
}
}
Non utilizzare i seguenti termini come variabili:
- timestamp raccolta
- createtimestamp
- event
- nomefile
- messaggio
- spazio dei nomi
- output
- numero di errori
- timestamp
- fuso orario
Archivia ogni valore dei dati in un campo UDM separato
Non archiviare più campi in un singolo campo UDM concatenandoli con un delimitatore. Di seguito è riportato un esempio:
"principal.user.first_name" => "first:%{first_name},last:%{last_name}"
Archivia invece ogni valore in un campo UDM separato.
"principal.user.first_name" => "%{first_name}"
"principal.user.last_name" => "%{last_name}"
Utilizza gli spazi anziché le tabulazioni nel codice
Non utilizzare le schede nel codice del parser. Utilizza solo spazi e rientra due spazi alla volta.
Non eseguire più azioni di unione in una singola operazione
Se unisci più campi in una singola operazione, i risultati potrebbero essere incoerenti. Puoi invece inserire le istruzioni merge
in
operazioni separate.
Sostituisci ad esempio il seguente:
mutate {
merge => {
"security_result.category_details" => "category_details"
"security_result.category_details" => "super_category_details"
}
}
Con questo:
mutate {
merge => {
"security_result.category_details" => "category_details"
}
}
mutate {
merge => {
"security_result.category_details" => "super_category_details"
}
}
Scelta delle espressioni condizionali if
e if else
Se il valore condizionale che stai verificando può avere una sola corrispondenza,
utilizza l'istruzione condizionale if else
. Questo approccio è leggermente più
efficiente. Tuttavia, in uno scenario in cui il valore testato potrebbe corrispondere
più di una volta, utilizza più istruzioni if
distinte e ordina le istruzioni
dal caso più generico a quello più specifico.
Scegli un set rappresentativo di file di log per testare le modifiche del parser
Una best practice consiste nel testare il codice del parser utilizzando campioni di log non elaborati con un'ampia varietà di formati. Ciò consente di trovare log univoci o casi limite che il parser potrebbe dover gestire.
Aggiungere commenti descrittivi al codice del parser
Aggiungi commenti al codice del parser che spieghino perché l'affermazione è importante, anziché la funzione dell'affermazione. Il commento aiuta chiunque mantenga l'analizzatore sintattico a seguire la procedura. Di seguito è riportato un esempio:
# 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}"
}
}
}
Inizializzare anticipatamente le variabili intermedie
Prima di estrarre i valori dal log originale non elaborato, inizializza le variabili intermedie che verranno utilizzate per archiviare i valori di test.
Questo impedisce che venga restituito un errore che indica che la variabile intermedia non esiste.
La seguente istruzione assegna il valore della variabile product
al
campo UDM metadata.product_name
.
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
Se la variabile product
non esiste, viene visualizzato il seguente errore:
"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"
Puoi aggiungere un'istruzione on_error
per rilevare l'errore. Di seguito è riportato un esempio:
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
on_error => "_error_does_not_exist"
}
L'istruzione di esempio precedente rileva correttamente l'errore di analisi in una variabile intermedia booleana chiamata _error_does_not_exist
. Non consente
di utilizzare la variabile product
in un'istruzione condizionale, ad esempio if
.
Di seguito è riportato un esempio:
if [product] != "" {
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
on_error => "_error_does_not_exist"
}
L'esempio precedente restituisce il seguente errore perché la clausola condizionale if
non supporta le istruzioni on_error
:
"generic::invalid_argument: pipeline failed: filter conditional (4) failed: failed to evaluate expression: generic::invalid_argument: "product" not found in state data"
Per risolvere il problema, aggiungi un blocco di istruzioni separato che inizializza le variabili intermedie prima di eseguire le istruzioni di filtro di estrazione (json
, csv
, xml
, kv
o grok
).
Di seguito è riportato un esempio.
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"
}
}
Lo snippet aggiornato del codice del parser gestisce più scenari utilizzando un'istruzione condizionale per verificare se il campo esiste. Inoltre, l'istruzione on_error
gestisce gli errori che potrebbero verificarsi.
Converti SHA-256 in base64
L'esempio seguente estrae il valore SHA-256, lo codifica in base64, converte i dati codificati in una stringa esadecimale, quindi sostituisce campi specifici con i valori estratti ed elaborati.
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}"
}
}
}
Gestire errori nelle istruzioni del parser
Non è raro che i log in entrata abbiano un formato di log imprevisto o che i dati siano formattati in modo errato.
Puoi creare il parser per gestire questi errori. Una best practice è aggiungere gestori on_error
al filtro di estrazione, quindi testare la variabile intermedia prima di passare al segmento successivo della logica del parser.
L'esempio seguente utilizza il filtro di estrazione json
con un'istruzione on_error
per impostare la variabile booleana _not_json
. Se il criterio _not_json
è impostato su true
, significa che la voce di log in entrata non era in un formato JSON valido e che la voce di log non è stata analizzata correttamente. Se la variabile _not_json
è false
, la voce di log in entrata era in un formato JSON valido.
# load the incoming log from the default message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
Puoi anche verificare se un campo è nel formato corretto. L'esempio seguente verifica se _not_json
è impostato su true
, per indicare che il log non era nel formato previsto.
# 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" }
}
}
Ciò garantisce che l'analisi non vada a buon fine se i log vengono importati con un formato errato per il tipo di log specificato.
Utilizza il filtro drop
con la variabile tag
in modo che la condizione venga acquisita nella tabella delle metriche di importazione in BigQuery.
TAG_UNSUPPORTED
TAG_MALFORMED_ENCODING
TAG_MALFORMED_MESSAGE
TAG_NO_SECURITY_VALUE
Il filtro drop
impedisce al parser di elaborare il log non elaborato, normalizzare i campi e creare un record UDM. Il log non elaborato originale viene ancora importato in Google Security Operations
e può essere cercato utilizzando la ricerca nei log non elaborata in Google Security Operations.
Il valore passato alla variabile tag
viene archiviato nel campo drop_reason_code
nella tabella delle metriche di importazione. Puoi eseguire una query ad hoc sulla tabella, come in questo esempio:
SELECT
log_type,
drop_reason_code,
COUNT(drop_reason_code) AS count
FROM `datalake.ingestion_metrics`
GROUP BY 1,2
ORDER BY 1 ASC
Risolvere gli errori di convalida
Quando crei un parser, potresti riscontrare errori relativi alla convalida. Ad esempio, nel record UDM non è impostato un campo obbligatorio. L'errore potrebbe essere simile al seguente:
Error: generic::unknown: invalid event 0: LOG_PARSING_GENERATED_INVALID_EVENT: "generic::invalid_argument: udm validation failed: target field is not set"
Il codice del parser viene eseguito correttamente, ma il record UDM generato non include tutti i campi UDM obbligatori come definito dal valore impostato su metadata.event_type
. Di seguito sono riportati alcuni esempi aggiuntivi che potrebbero causare questo errore:
- Se
metadata.event_type
èUSER_LOGIN
e il campo UDMtarget.user value
non è impostato. - Se
metadata.event_type
èNETWORK_CONNECTION
e iltarget.hostname
campo UDM non è impostato.
Per ulteriori informazioni sul campo UDM metadata.event_type
e su quelli obbligatori, consulta la guida all'uso dell'UDM.
Un'opzione per risolvere questo tipo di errore è iniziare impostando valori statici per i campi UDM. Dopo aver definito tutti i campi UDM necessari, esamina il log non elaborato originale per vedere quali valori analizzare e salvare nel record UDM. Se il log originale non elaborato non contiene determinati campi, potrebbe essere necessario impostare valori predefiniti.
Di seguito è riportato un modello di esempio, specifico per un tipo di evento USER_LOGIN
, che illustra questo approccio.
Tieni presente quanto segue:
- Il modello inizializza le variabili intermedie e imposta ciascuna su una stringa statica.
- Il codice nella sezione Assegnazione campi imposta i valori nelle variabili intermedie nei campi UDM.
Puoi espandere questo codice aggiungendo ulteriori variabili intermedie e campi UDM. Dopo aver identificato tutti i campi UDM che devono essere compilati, segui questi passaggi:
Nella sezione Configurazione di input, aggiungi il codice che estrae i campi dal log non elaborato originale e imposta i valori sulle variabili intermedie.
Nella sezione Date Extract, aggiungi il codice che estrae il timestamp dell'evento dal log non elaborato originale, lo trasforma e lo imposta come variabile intermedia.
Se necessario, sostituisci il valore inizializzato impostato in ogni variabile intermedia con una stringa vuota.
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"
}
}
}
Analizzare il testo non strutturato con una funzione Grok
Quando utilizzi una funzione Grok per estrarre valori da testo non strutturato, puoi
utilizzare pattern Grok predefiniti ed istruzioni di espressioni regolari. I pattern Grok semplificano la lettura
del codice. Se l'espressione regolare non include caratteri abbreviati (come \w
, \s
), puoi copiare e incollare l'istruzione direttamente nel codice del parser.
Poiché i pattern Grok sono un livello di astrazione aggiuntivo nell'istruzione, potrebbero rendere la risoluzione dei problemi più complessa quando si verifica un errore. Di seguito è riportato un esempio di funzione Grok che contiene sia pattern Grok predefiniti che espressioni regolari.
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+).*"
]
}
}
Un'istruzione di estrazione senza pattern Grok potrebbe offrire prestazioni migliori. Nel seguente esempio, la corrispondenza richiede meno della metà dei passaggi di elaborazione. Questa è una considerazione importante per un'origine log con volumi potenzialmente elevati.
Comprendere le differenze tra le espressioni regolari RE2 e PCRE
I parser di Google Security Operations utilizzano RE2 come motore delle espressioni regolari. Se hai familiarità con la sintassi PCRE, potresti notare differenze. Ecco un esempio:
Di seguito è riportata un'istruzione PCRE: (?<_custom_field>\w+)\s
Di seguito è riportata un'istruzione RE2 per il codice del parser: (?P<_custom_field>\\w+)\\s
Assicurati di utilizzare l'interpretazione letterale per i caratteri di escape
Google Security Operations archivia i dati di log non elaborati in entrata in formato con codifica JSON. Ciò garantisce che le stringhe di caratteri che sembrano essere espressioni regolari come forma abbreviata vengano interpretate come stringa letterale. Ad esempio, \t
viene interpretato come stringa letterale, anziché come carattere di tabulazione.
L'esempio seguente è un log originale non elaborato e il log in formato con codifica JSON.
Nota il carattere di escape aggiunto prima di ogni barra rovesciata
che circonda il termine entry
.
Di seguito è riportato il log originale non elaborato:
field=\entry\
Di seguito è riportato il log convertito nel formato con codifica JSON:
field=\\entry\\
Quando utilizzi un'espressione regolare nel codice del parser, devi aggiungere altri caratteri di escape se desideri estrarre solo il valore. Per trovare una barra rovesciata nel log non elaborato originale, utilizza quattro barre rovesciate nell'istruzione di estrazione.
Di seguito è riportata un'espressione regolare per il codice del parser:
^field=\\\\(?P<_value>.*)\\\\$
Di seguito è riportato il risultato generato. Il gruppo denominato _value
memorizza il termine entry
:
"_value": "entry"
Quando sposti un'istruzione di espressione regolare standard nel codice dell'analizzatore sintattico, esegui l'escape dei caratteri abbreviati delle espressioni regolari nell'istruzione di estrazione.
Ad esempio, modifica \s
in \\s
.
Lascia invariati i caratteri speciali dell'espressione regolare se viene eseguito il doppio escape nell'istruzione di estrazione. Ad esempio, \\
rimane invariato come \\
.
Di seguito è riportata un'espressione regolare standard:
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
La seguente espressione regolare è stata modificata per funzionare nel codice del parser.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
La tabella seguente riassume i casi in cui un'espressione regolare standard deve includere caratteri di escape aggiuntivi prima di includerla nel codice dell'analizzatore sintattico.
Espressione regolare | Espressione regolare modificata per il codice del parser | Descrizione della modifica |
---|---|---|
\s |
\\s |
I caratteri abbreviati devono essere preceduti dal carattere di escape. |
\. |
\\. |
I caratteri riservati devono essere preceduti dal carattere di escape. |
\\" |
\\\" |
I caratteri riservati devono essere preceduti dal carattere di escape. |
\] |
\\] |
I caratteri riservati devono essere preceduti dal carattere di escape. |
\| |
\\| |
I caratteri riservati devono essere preceduti dal carattere di escape. |
[^\\]+ |
[^\\\\]+ |
I caratteri speciali di un gruppo di classi di caratteri devono essere preceduti dal carattere di escape. |
\\\\ |
\\\\ |
I caratteri speciali esterni a un gruppo di classi di caratteri o i caratteri abbreviati non richiedono caratteri di escape aggiuntivi. |
Le espressioni regolari devono includere un gruppo di acquisizione denominato
Un'espressione regolare, come "^.*$"
, è una sintassi RE2 valida. Tuttavia, il codice del parser
non riesce e restituisce il seguente errore:
"ParseLogEntry failed: pipeline failed: filter grok (0) failed: failed to parse data with all match
patterns"
Devi aggiungere un gruppo di acquisizione valido all'espressione. Se utilizzi i pattern Grok, questi includono per impostazione predefinita un gruppo di acquisizione denominato. Quando utilizzi gli override delle espressioni regolari, assicurati di includere un gruppo denominato.
Di seguito è riportato un esempio di espressione regolare nel codice del parser:
"^(?P<_catchall>.*$)"
Di seguito è riportato il risultato, che mostra il testo assegnato al gruppo denominato _catchall
.
"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."
Utilizza un gruppo con nome catchall per iniziare mentre crei l'espressione
Quando crei un'istruzione di estrazione, inizia con un'espressione che rileva più di quanto vuoi. Quindi, espandi l'espressione un campo alla volta.
L'esempio seguente inizia utilizzando un gruppo denominato (_catchall
) che corrisponde all'intero messaggio. Poi crea l'espressione gradualmente, abbinando
altre parti del testo. A ogni passaggio, il gruppo denominato _catchall
contiene meno del testo originale. Continua e ripeti un passaggio alla volta per
corrispondere al messaggio finché non avrai più bisogno del gruppo denominato _catchall
.
Passaggio | Espressione regolare nel codice del parser | Output del gruppo di acquisizione denominato _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\". |
Continua fino a quando l'espressione corrisponde all'intera stringa di testo. |
Esegui l'escape dei caratteri brevi nell'espressione regolare
Ricorda di eseguire l'escape dei caratteri abbreviati delle espressioni regolari quando utilizzi l'espressione nel codice dell'analizzatore sintattico. Di seguito è riportato un esempio di stringa di testo e l'espressione regolare standard che estrae la prima parola, This
.
This is a sample log.
La seguente espressione regolare standard estrae la prima parola, This
.
Tuttavia, quando esegui questa espressione nel codice dell'analizzatore sintattico, nel risultato manca la lettera
s
.
Espressione regolare standard | Output del gruppo di acquisizione denominato _firstWord |
---|---|
"^(?P<_firstWord>[^\s]+)\s.*$" |
"_firstWord": "Thi", |
Questo perché le espressioni regolari nel codice del parser richiedono un carattere di escape aggiuntivo aggiunto ai caratteri brevi. Nell'esempio precedente, \s
deve essere modificato in \\s
.
Espressione regolare modificata per il codice del parser | Output del gruppo di acquisizione denominato _firstWord |
---|---|
"^(?P<_firstWord>[^\\s]+)\\s.*$" |
"_firstWord": "This", |
Questo vale solo per i caratteri brevi, come \s
, \r
e \t
.
Altri caratteri, come "`, non devono essere preceduti dal carattere di escape.
Un esempio completo
Questa sezione descrive le regole precedenti come esempio end-to-end. Di seguito è riportata una stringa di testo non strutturata e un'espressione regolare standard scritta per analizzare la stringa. Infine, include l'espressione regolare modificata che funziona nel codice del parser.
Di seguito è riportata la stringa di testo originale.
User "BOB" logged on to workstation "DESKTOP-01".
Di seguito è riportata un'espressione regolare RE2 standard che analizza la stringa di testo.
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
Questa espressione estrae i seguenti campi.
Gruppo di corrispondenze | Posizione carattere | Stringa di testo |
---|---|---|
Corrispondenza completa | 0-53 | User \"BOB\" logged on to workstation \"DESKTOP-01\". |
Gruppo "_user" | 7-10 | BOB |
Gruppo 2. | 13-22 | logged on |
Raggruppa "_device" | 40-50 | DESKTOP-01 |
Questa è l'espressione modificata. L'espressione regolare RE2 standard è stata modificata per funzionare nel codice del parser.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$