Suggerimenti e risoluzione dei problemi relativi alla scrittura dei parser
Questo documento descrive i problemi che potresti riscontrare quando scrivi il codice del parser.
Quando scrivi il codice del parser, potresti riscontrare errori quando le istruzioni di analisi non funzionano come previsto. Le situazioni che potrebbero generare errori sono le seguenti:
- Un pattern
Grok
non va a buon fine - Un'operazione
rename
oreplace
non riesce - Errori di sintassi nel codice dell'analizzatore
Pratiche comuni nel codice del parser
Le sezioni seguenti descrivono le best practice, i suggerimenti e le soluzioni per aiutarti a risolvere i problemi.
Evita di utilizzare punti o trattini nei nomi delle variabili.
L'utilizzo di trattini e punti nei nomi delle variabili può causare un comportamento imprevisto, spesso quando vengono eseguite operazioni merge
per memorizzare i valori nei campi UDM. Potresti anche riscontrare problemi di analisi intermittenti.
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
Alcune 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 viene utilizzata 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
, viene visualizzato un messaggio di errore relativo a un conflitto di nomi.
Rinomina la variabile intermedia in un altro nome o utilizza il termine event1
come
un prefisso nei nomi dei campi UDM e nell'istruzione @output
.
La parola timestamp
rappresenta il timestamp del log non elaborato originale creato. R
valore impostato in questa variabile intermedia viene salvato nella
metadata.event_timestamp
campo UDM. 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 di analisi del log non elaborato.
# 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 estratte dal log non elaborato originale e archiviate nella variabile intermedia when
.
# Save the event timestamp to timestamp variable
mutate {
rename => {
"when" => "timestamp"
}
}
Non utilizzare i seguenti termini come variabili:
- collectiontimestamp
- createtimestamp
- event
- filename
- messaggio
- spazio dei nomi
- output
- numero di errori
- timestamp
- fuso orario
Memorizza ogni valore di dati in un campo UDM separato
Non memorizzare 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 tabulazioni nel codice dell'analizzatore. Utilizza solo spazi e rientra due spazi alla volta.
Non eseguire più azioni di unione in una singola operazione
Se unisci più campi in un'unica operazione, potresti ottenere risultati incoerenti. Inserisci invece le istruzioni merge
in operazioni separate.
Ad esempio, sostituisci il seguente esempio:
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
rispetto a if else
Se il valore condizionale che stai testando può avere una sola corrispondenza,
utilizza l'istruzione condizionale if else
. Questo approccio è leggermente più
efficiente. Tuttavia, se hai 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 diversi formati. In questo modo puoi trovare log o casi limite unici che il parser potrebbe dover gestire.
Aggiungere commenti descrittivi al codice dell'analizzatore
Aggiungi commenti al codice del parser che spieghino perché l'affermazione è importante, anziché rispetto all'affermazione. Il commento aiuta chiunque gestisca il parser a seguire il flusso. 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}"
}
}
}
Inizializza le variabili intermedie in anticipo
Prima di estrarre i valori dal log non elaborato originale, inizializza il valore intermedio e variabili che verranno utilizzate per archiviare i valori di test.
Ciò impedisce la restituzione di un errore che indica che la variabile intermedia inesistente.
La seguente istruzione assegna il valore nella variabile product
a
nel 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 questo problema, aggiungi un blocco di istruzioni separato che inizializza l'intermedio
prima di eseguire le istruzioni del 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
l'istruzione condizionale per verificare se il campo esiste. Inoltre, l'istruzione
on_error
gestisce gli errori che potrebbero verificarsi.
Converti SHA-256 in base64
Il seguente esempio estrae il valore SHA-256, lo codifica in base64, converte i dati codificati in una stringa esadecimale e poi 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 gli errori negli statement del parser
Non è raro che i log in entrata siano in un formato di log imprevisto o i dati non sono formattati correttamente.
Puoi creare il parser per gestire questi errori. Una best practice è aggiungere gestori on_error
al filtro di estrazione e poi 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 on_error
per impostare la variabile booleana _not_json
. Se _not_json
è impostato su
true
, significa che la voce di log in arrivo non era in formato JSON valido e la
voce di log non è stata analizzata correttamente. Se la variabile _not_json
è false
,
la voce di log in arrivo era in 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. Nell'esempio che segue
verifica se _not_json
è impostato su true
, indicando 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 all'analizzatore di elaborare il log non elaborato, normalizzare i campi e creare un record UDM. Il log non elaborato originale viene comunque importato in Google Security Operations
e può essere cercato utilizzando la ricerca dei log non elaborati in Google Security Operations.
Il valore passato alla variabile tag
viene memorizzato nel campo drop_reason_code
della tabella Metriche di importazione. Puoi eseguire una query ad hoc sulla tabella simile alla seguente:
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
Durante la creazione di un parser, potresti riscontrare errori relativi alla convalida, ad esempio Ad esempio, non è impostato un campo obbligatorio nel record UDM. L'errore potrebbe avere il seguente aspetto:
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 non il record UDM generato
Includi tutti i campi UDM obbligatori come definito dal valore impostato su metadata.event_type
. Di seguito sono riportati altri esempi che possono 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 per i campi obbligatori
consulta la guida all'uso dell'UDM.
Un'opzione per risolvere questo tipo di errore è iniziare impostando valori statici su UDM. campi. 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 non elaborato originale 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 dei campi imposta i valori nelle variabili intermedie ai campi UDM.
Puoi espandere questo codice aggiungendo altre variabili intermedie e campi UDM. Dopo aver identificato tutti i campi UDM che devono essere compilati, svolgi i seguenti passaggi:
Nella sezione Configurazione di input, aggiungi il codice che estrae i campi da il log originale non elaborato 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 sulla 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"
}
}
}
Analizza il testo non strutturato utilizzando 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. Motivi grok
facilitano la lettura del codice. Se l'espressione regolare non include caratteri di abbreviazione (ad esempio \w
, \s
), puoi copiare e incollare l'istruzione direttamente nel codice del parser.
Poiché i pattern Grok sono un ulteriore livello di astrazione nell'istruzione, possono procedure di risoluzione dei problemi più complesse quando si verifica un errore. Di seguito è riportato un esempio di funzione Grok che contiene sia pattern Grok predefiniti sia 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 avere un rendimento migliore. Per quello che segue richiede la corrispondenza con meno della metà dei passaggi di elaborazione. Per un'origine log con un volume potenzialmente elevato, questa è una considerazione importante.
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, puoi 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 dei caratteri di escape
Google Security Operations archivia i dati di log non elaborati in entrata in formato con codifica JSON. Questo serve per assicurarti che le stringhe di caratteri che sembrano essere una scorciatoia per le espressioni regolari vengano interpretate come stringa letterale. Ad esempio, \t
viene interpretato come la
stringa letterale anziché come un carattere di tabulazione.
L'esempio seguente mostra un log originale non elaborato e il log in formato con codifica JSON.
Nota il carattere di escape aggiunto prima di ogni carattere barra inversa
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 un carattere di escape aggiuntivo per estrarre solo il valore. Per trovare una barra rovesciata in del 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, utilizza il comando Esc
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 utilizzato il doppio carattere di escape nella
una dichiarazione 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 viene modificata per funzionare all'interno del codice del parser.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
La tabella seguente riassume quando un'espressione regolare standard deve includere caratteri di escape aggiuntivi prima di essere inclusa nel codice del parser.
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 all'interno di un gruppo di classi di caratteri devono essere preceduti dal carattere di escape. |
\\\\ |
\\\\ |
Caratteri speciali esterni a un gruppo di classi di caratteri o caratteri brevi non richiedono un carattere di escape aggiuntivo. |
Le espressioni regolari devono includere un gruppo di cattura denominato
Un'espressione regolare, ad esempio "^.*$"
, è una sintassi RE2 valida. Tuttavia, nel 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 cattura valido all'espressione. Se usi Grok tra cui, per impostazione predefinita, un gruppo di acquisizione denominato. Quando utilizzi le sostituzioni di 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 rilevi più di quanto si voglia. Quindi, espandi l'espressione un campo alla volta.
L'esempio seguente inizia utilizzando un gruppo denominato (_catchall
) che corrisponde all'intero messaggio. Quindi, genera l'espressione in modo graduale abbinando altre parti del testo. A ogni passaggio, il gruppo denominato _catchall
contiene meno testo originale. Continua e ripeti un passaggio alla volta per
corrispondere al messaggio fino a quando non hai 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 finché l'espressione non corrisponde all'intera stringa di testo. |
Caratteri di escape per i caratteri abbreviati nell'espressione regolare
Ricorda di eseguire l'escape dei caratteri brevi delle espressioni regolari quando utilizzi il metodo
nel codice del parser. Di seguito è riportato un esempio di stringa di testo e
un'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 del parser, nel risultato manca la letteras
.
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 sfuggita aggiuntivo aggiunto ai caratteri di abbreviazione. Nell'esempio precedente, \s
deve essere modificato in \\s
.
Espressione regolare rivista per il codice del parser | Output del gruppo di acquisizione denominato _firstWord |
---|---|
"^(?P<_firstWord>[^\\s]+)\\s.*$" |
"_firstWord": "This", |
Questo vale solo per i caratteri di abbreviazione, come \s
, \r
e \t
.
Altri caratteri, come ", non richiedono ulteriori interpretazioni letterali.
Un esempio completo
Questa sezione descrive le regole precedenti come esempio end-to-end. Ecco un stringa di testo non strutturata e l'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 del 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>[^\\\\]+)\\\"\\.$