Tipps und Fehlerbehebung beim Schreiben von Parsern
In diesem Dokument werden Probleme beschrieben, die beim Schreiben von Parsercode auftreten können.
Beim Schreiben von Parsercode können Fehler auftreten, wenn die Parsing-Anweisungen nicht wie erwartet funktionieren. Folgende Situationen können Fehler verursachen:
- Ein
Grok
-Muster schlägt fehl - Ein
rename
- oderreplace
-Vorgang schlägt fehl - Syntaxfehler im Parsercode
Gängige Vorgehensweisen im Parsercode
In den folgenden Abschnitten werden die Best Practices, Tipps und Lösungen zur Behebung von Problemen beschrieben.
Vermeiden Sie die Verwendung von Punkten oder Bindestrichen in Variablennamen
Die Verwendung von Bindestrichen und Punkten in Variablennamen kann zu unerwartetem Verhalten führen, was häufig bei merge
-Vorgängen zum Speichern von Werten in UDM-Feldern der Fall ist. Auch beim Parsen können zeitweise Probleme auftreten.
Verwenden Sie beispielsweise nicht die folgenden Variablennamen:
my.variable.result
my-variable-result
Verwenden Sie stattdessen den folgenden Variablennamen: my_variable_result
.
Verwenden Sie in Variablennamen keine Begriffe mit besonderer Bedeutung.
Bestimmte Wörter wie event
und timestamp
können im Parsercode eine besondere Bedeutung haben.
Der String event
wird häufig zur Darstellung eines einzelnen UDM-Eintrags verwendet und in der @output
-Anweisung verwendet. Wenn eine Lognachricht ein Feld namens event
enthält oder Sie eine Zwischenvariable mit dem Namen event
definieren und der Parsercode in der @output
-Anweisung das Wort event
verwendet, erhalten Sie eine Fehlermeldung zu einem Namenskonflikt.
Benennen Sie die Zwischenvariable um oder verwenden Sie den Begriff event1
als Präfix in UDM-Feldnamen und in der @output
-Anweisung.
Das Wort timestamp
steht für den erstellten Zeitstempel des ursprünglichen Rohprotokolls. Ein in dieser Zwischenvariable festgelegter Wert wird im UDM-Feld metadata.event_timestamp
gespeichert. Der Begriff @timestamp
steht für das Datum und die Uhrzeit, zu der das Log-Rohdaten zum Erstellen eines UDM-Eintrags geparst wurde.
Im folgenden Beispiel wird für das UDM-Feld metadata.event_timestamp
das Datum und die Uhrzeit des Parsens des Rohlogs festgelegt.
# Save the log parse date and time to the timestamp variable
mutate {
rename => {
"@timestamp" => "timestamp"
}
}
Im folgenden Beispiel werden für das UDM-Feld metadata.event_timestamp
das Datum und die Uhrzeit festgelegt, die aus dem ursprünglichen Rohlog extrahiert und in der Zwischenvariable when
gespeichert werden.
# Save the event timestamp to timestamp variable
mutate {
rename => {
"when" => "timestamp"
}
}
Verwenden Sie die folgenden Begriffe nicht als Variablen:
- Sammlungszeitstempel
- Zeitstempel erstellen
- event
- filename
- nachricht
- Namespace
- Ausgabe
- onerrorcount
- timestamp
- Zeitzone
Jeden Datenwert in einem separaten UDM-Feld speichern
Speichern Sie nicht mehrere Felder in einem einzigen UDM-Feld, indem Sie sie mit einem Trennzeichen verketten. Hier ein Beispiel:
"principal.user.first_name" => "first:%{first_name},last:%{last_name}"
Speichern Sie stattdessen jeden Wert in einem separaten UDM-Feld.
"principal.user.first_name" => "%{first_name}"
"principal.user.last_name" => "%{last_name}"
Leerzeichen anstelle von Tabulatoren im Code verwenden
Im Parsercode dürfen keine Tabs verwendet werden. Verwenden Sie nur Leerzeichen und rücken Sie 2 Leerzeichen gleichzeitig ein.
Führen Sie nicht mehrere Zusammenführungsaktionen in einem einzigen Vorgang aus.
Wenn Sie mehrere Felder in einem einzigen Vorgang zusammenführen, kann dies zu uneinheitlichen Ergebnissen führen. Setzen Sie stattdessen merge
-Anweisungen in separate Vorgänge.
Ersetzen Sie beispielsweise das folgende Beispiel:
mutate {
merge => {
"security_result.category_details" => "category_details"
"security_result.category_details" => "super_category_details"
}
}
durch diesen Codeblock:
mutate {
merge => {
"security_result.category_details" => "category_details"
}
}
mutate {
merge => {
"security_result.category_details" => "super_category_details"
}
}
Bedingte if
-Ausdrücke im Vergleich zu if else
-Ausdrücken auswählen
Wenn der bedingte Wert, den Sie testen, immer nur eine Übereinstimmung haben kann, verwenden Sie die bedingte Anweisung if else
. Dieser Ansatz ist etwas effizienter. Wenn der getestete Wert jedoch mehrmals übereinstimmen könnte, sollten Sie mehrere unterschiedliche if
-Anweisungen verwenden und die Anweisungen vom allgemeinsten zum spezifischsten Fall sortieren.
Wählen Sie einen repräsentativen Satz von Protokolldateien zum Testen von Parseränderungen aus
Eine Best Practice besteht darin, Parsercode mit unformatierten Logbeispielen mit einer Vielzahl von Formaten zu testen. So können Sie einzelne Logs oder Grenzfälle finden, die der Parser möglicherweise bearbeiten muss.
Beschreibende Kommentare zum Parsercode hinzufügen
Fügen Sie dem Parsercode Kommentare hinzu, die erklären, warum die Anweisung wichtig ist und nicht, was sie bewirkt. Der Kommentar hilft allen, die den Parser pflegen, den Ablauf zu verfolgen. Hier ein Beispiel:
# 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}"
}
}
}
Zwischenvariablen frühzeitig initialisieren
Bevor Sie Werte aus dem ursprünglichen Rohlog extrahieren, müssen Sie Zwischenvariablen initialisieren, die zum Speichern von Testwerten verwendet werden.
Dadurch wird verhindert, dass ein Fehler zurückgegeben wird, der angibt, dass die Zwischenvariable nicht vorhanden ist.
Mit der folgenden Anweisung wird der Wert in der Variablen product
dem UDM-Feld metadata.product_name
zugewiesen.
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
Wenn die Variable product
nicht vorhanden ist, wird der folgende Fehler ausgegeben:
"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"
Sie können eine on_error
-Anweisung hinzufügen, um den Fehler abzufangen. Hier ein Beispiel:
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
on_error => "_error_does_not_exist"
}
Mit der vorherigen Beispielanweisung wird der Parsing-Fehler erfolgreich in eine boolesche Zwischenvariable namens _error_does_not_exist
abgefangen. Sie können die Variable product
nicht in einer bedingten Anweisung wie if
verwenden.
Hier ein Beispiel:
if [product] != "" {
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
on_error => "_error_does_not_exist"
}
Das vorherige Beispiel gibt den folgenden Fehler zurück, da die bedingte if
-Klausel keine on_error
-Anweisungen unterstützt:
"generic::invalid_argument: pipeline failed: filter conditional (4) failed: failed to evaluate expression: generic::invalid_argument: "product" not found in state data"
Zur Lösung dieses Problems fügen Sie einen separaten Anweisungsblock hinzu, der die Zwischenvariablen initialisiert, bevor die Extraktionsfilteranweisungen (json
, csv
, xml
, kv
oder grok
) ausgeführt werden.
Folgendes ist ein Beispiel.
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"
}
}
Das aktualisierte Parsercode-Snippet verarbeitet die verschiedenen Szenarien und prüft mithilfe einer bedingten Anweisung, ob das Feld vorhanden ist. Darüber hinaus behandelt die on_error
-Anweisung Fehler, die auftreten können.
SHA-256 in base64 konvertieren
Im folgenden Beispiel wird der SHA-256-Wert extrahiert, in base64 codiert, die codierten Daten in einen Hexadezimalstring umgewandelt und dann bestimmte Felder durch die extrahierten und verarbeiteten Werte ersetzt.
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}"
}
}
}
Fehler in Parseranweisungen verarbeiten
Es ist nicht ungewöhnlich, dass eingehende Logs ein unerwartetes Logformat haben oder falsch formatierte Daten enthalten.
Der Parser kann so erstellt werden, dass er diese Fehler behandelt. Es empfiehlt sich, dem Extraktionsfilter on_error
-Handler hinzuzufügen und dann die Zwischenvariable zu testen, bevor mit dem nächsten Segment der Parserlogik fortgefahren wird.
Im folgenden Beispiel wird der Extraktionsfilter json
mit einer on_error
-Anweisung verwendet, um die boolesche Variable _not_json
festzulegen. Wenn _not_json
auf true
gesetzt ist, hatte der eingehende Logeintrag kein gültiges JSON-Format und er konnte nicht erfolgreich geparst werden. Wenn die Variable _not_json
den Wert false
hat, hatte der eingehende Logeintrag ein gültiges JSON-Format.
# load the incoming log from the default message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
Sie können auch testen, ob ein Feld das richtige Format hat. Im folgenden Beispiel wird geprüft, ob _not_json
auf true
gesetzt ist, was darauf hinweist, dass das Log nicht das erwartete Format hat.
# 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" }
}
}
So wird sichergestellt, dass das Parsen nicht fehlschlägt, wenn Logs mit einem falschen Format für den angegebenen Logtyp aufgenommen werden.
Verwenden Sie den Filter drop
mit der Variablen tag
, damit die Bedingung in der Tabelle mit Aufnahmemesswerten in BigQuery erfasst wird.
TAG_UNSUPPORTED
TAG_MALFORMED_ENCODING
TAG_MALFORMED_MESSAGE
TAG_NO_SECURITY_VALUE
Der Filter drop
verhindert, dass der Parser das Rohlog verarbeitet, die Felder normalisiert und einen UDM-Eintrag erstellt. Das ursprüngliche Rohlog wird weiterhin in Chronicle aufgenommen und kann mit der unformatierten Logsuche in Chronicle durchsucht werden.
Der an die Variable tag
übergebene Wert wird in der Tabelle mit den Aufnahmemesswerten im Feld drop_reason_code
gespeichert. Sie können eine Ad-hoc-Abfrage für die Tabelle ausführen, die in etwa so aussieht:
SELECT
log_type,
drop_reason_code,
COUNT(drop_reason_code) AS count
FROM `datalake.ingestion_metrics`
GROUP BY 1,2
ORDER BY 1 ASC
Validierungsfehler beheben
Beim Erstellen eines Parsers können Fehler im Zusammenhang mit der Validierung auftreten, z. B., wenn im UDM-Eintrag kein Pflichtfeld festgelegt wurde. Der Fehler könnte etwa so aussehen:
Error: generic::unknown: invalid event 0: LOG_PARSING_GENERATED_INVALID_EVENT: "generic::invalid_argument: udm validation failed: target field is not set"
Der Parsercode wird erfolgreich ausgeführt, der generierte UDM-Eintrag enthält jedoch nicht alle erforderlichen UDM-Felder, wie durch den Wert definiert, der auf metadata.event_type
gesetzt ist. Im Folgenden finden Sie weitere Beispiele, die diesen Fehler verursachen können:
- Wenn
metadata.event_type
den WertUSER_LOGIN
hat und das UDM-Feldtarget.user value
nicht festgelegt ist. - Wenn
metadata.event_type
den WertNETWORK_CONNECTION
hat und das UDM-Feldtarget.hostname
nicht festgelegt ist.
Weitere Informationen zum UDM-Feld metadata.event_type
und zu den erforderlichen Feldern finden Sie im UDM-Nutzungsleitfaden.
Eine Möglichkeit zur Behebung dieses Fehlertyps besteht darin, statische Werte auf UDM-Felder zu setzen. Nachdem Sie alle erforderlichen UDM-Felder definiert haben, prüfen Sie das ursprüngliche Rohlog, um zu sehen, welche Werte geparst und im UDM-Eintrag gespeichert werden müssen. Wenn das ursprüngliche Rohlog bestimmte Felder nicht enthält, müssen Sie möglicherweise Standardwerte festlegen.
Im Folgenden finden Sie eine Beispielvorlage, die für einen USER_LOGIN
-Ereignistyp spezifisch ist und diesen Ansatz veranschaulicht.
Beachten Sie Folgendes:
- Die Vorlage initialisiert Zwischenvariablen und legt jede auf einen statischen String fest.
- Der Code im Abschnitt Feldzuweisung legt die Werte in Zwischenvariablen in UDM-Felder fest.
Sie können diesen Code erweitern, indem Sie zusätzliche Zwischenvariablen und UDM-Felder hinzufügen. Nachdem Sie alle UDM-Felder ermittelt haben, die ausgefüllt werden müssen, gehen Sie so vor:
Fügen Sie im Bereich Input Configuration (Eingabekonfiguration) Code hinzu, der Felder aus dem ursprünglichen Rohlog extrahiert und die Werte als Zwischenvariablen festlegt.
Fügen Sie im Bereich Date Extract (Datumsextraktion) Code hinzu, der den Ereigniszeitstempel aus dem ursprünglichen Rohlog extrahiert, umwandelt und auf die Zwischenvariable festlegt.
Ersetzen Sie bei Bedarf den in jeder Zwischenvariablen festgelegten initialisierten Wert durch einen leeren String.
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"
}
}
}
Unstrukturierten Text mit einer Grok-Funktion parsen
Wenn Sie mit einer Grok-Funktion Werte aus unstrukturiertem Text extrahieren, können Sie vordefinierte Grok-Muster und Anweisungen für reguläre Ausdrücke verwenden. Grok-Muster sorgen dafür, dass
Code leichter zu lesen ist. Wenn der reguläre Ausdruck keine Kurzzeichen wie \w
oder \s
enthält, können Sie die Anweisung kopieren und direkt in den Parsercode einfügen.
Da Grok-Muster eine zusätzliche Abstraktionsebene in der Anweisung sind, können sie die Fehlerbehebung komplexer machen, wenn ein Fehler auftritt. Das folgende Beispiel zeigt eine Grok-Funktion, die sowohl vordefinierte Grok-Muster als auch reguläre Ausdrücke enthält.
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+).*"
]
}
}
Eine Extraktionsanweisung ohne Grok-Muster kann leistungsfähiger sein. Im folgenden Beispiel sind für den Abgleich weniger als die Hälfte der Verarbeitungsschritte erforderlich. Bei einer Protokollquelle mit potenziell hohem Volumen ist dies ein wichtiger Aspekt.
Unterschiede zwischen regulären Ausdrücken für RE2 und PCRE verstehen
Chronicle-Parser verwenden RE2 als Engine für reguläre Ausdrücke. Wenn Sie mit der PCRE-Syntax vertraut sind, fallen Ihnen möglicherweise Unterschiede auf. Hier ein Beispiel:
Das folgende Beispiel zeigt eine PCRE-Anweisung: (?<_custom_field>\w+)\s
Im Folgenden findest du eine RE2-Anweisung für Parsercode: (?P<_custom_field>\\w+)\\s
Achte darauf, die Escape-Zeichen zu maskieren
Chronicle speichert eingehende Log-Rohdaten im JSON-codierten Format. Dadurch wird sichergestellt, dass Zeichenstrings, die als Abkürzung für reguläre Ausdrücke zu sein scheinen, als Literalstring interpretiert werden. Beispielsweise wird \t
als literaler String und nicht als Tabulatorzeichen interpretiert.
Das folgende Beispiel zeigt ein ursprüngliches Rohlog und das JSON-codierte Formatprotokoll.
Vor jedem umgekehrten Schrägstrich um den Begriff entry
wird ein Escapezeichen eingefügt.
Das ist das ursprüngliche Rohprotokoll:
field=\entry\
Das folgende Log wurde in ein JSON-codiertes Format konvertiert:
field=\\entry\\
Wenn Sie einen regulären Ausdruck im Parsercode verwenden, müssen Sie zusätzliche Escapezeichen hinzufügen, wenn Sie nur den Wert extrahieren möchten. Für einen Abgleich mit einem umgekehrten Schrägstrich im ursprünglichen Rohlog verwenden Sie vier umgekehrte Schrägstriche in der Extraktionsanweisung.
Im Folgenden finden Sie einen regulären Ausdruck für Parsercode:
^field=\\\\(?P<_value>.*)\\\\$
Das folgende Ergebnis ist das generierte Ergebnis. In der benannten Gruppe _value
wird der Begriff entry
gespeichert:
"_value": "entry"
Wenn Sie eine Standardanweisung für reguläre Ausdrücke in einen Parsercode verschieben, müssen Sie die Kurzzeichen der regulären Ausdrücke in der Extraktionsanweisung mit Escapezeichen versehen.
Ändern Sie beispielsweise \s
in \\s
.
Lassen Sie die Sonderzeichen für reguläre Ausdrücke unverändert, wenn Sie in der Extraktionsanweisung doppelt maskiert sind. \\
bleibt beispielsweise unverändert \\
.
Im Folgenden finden Sie einen regulären regulären Ausdruck:
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
Der folgende reguläre Ausdruck wurde so geändert, dass er im Parsercode funktioniert.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
In der folgenden Tabelle wird zusammengefasst, wann ein regulärer Standardausdruck zusätzliche Escape-Zeichen enthalten muss, bevor er in den Parsercode aufgenommen wird.
Regulärer Ausdruck | Geänderter regulärer Ausdruck für Parsercode | Beschreibung der Änderung |
---|---|---|
\s |
\\s |
Kurzzeichen müssen maskiert werden. |
\. |
\\. |
Reservierte Zeichen müssen maskiert werden. |
\\" |
\\\" |
Reservierte Zeichen müssen maskiert werden. |
\] |
\\] |
Reservierte Zeichen müssen maskiert werden. |
\| |
\\| |
Reservierte Zeichen müssen maskiert werden. |
[^\\]+ |
[^\\\\]+ |
Sonderzeichen innerhalb einer Zeichenklassengruppe müssen maskiert werden. |
\\\\ |
\\\\ |
Für Sonderzeichen außerhalb einer Zeichenklassengruppe oder Kurzzeichen sind keine zusätzlichen Escapezeichen erforderlich. |
Reguläre Ausdrücke müssen eine benannte Erfassungsgruppe enthalten.
Ein regulärer Ausdruck wie "^.*$"
ist eine gültige RE2-Syntax. Im Parsercode schlägt er jedoch mit dem folgenden Fehler fehl:
"ParseLogEntry failed: pipeline failed: filter grok (0) failed: failed to parse data with all match
patterns"
Sie müssen dem Ausdruck eine gültige Erfassungsgruppe hinzufügen. Wenn Sie Grok-Muster verwenden, enthalten diese standardmäßig eine benannte Erfassungsgruppe. Wenn Sie Überschreibungen regulärer Ausdrücke verwenden, müssen Sie eine benannte Gruppe einschließen.
Hier ein Beispiel für einen regulären Ausdruck im Parsercode:
"^(?P<_catchall>.*$)"
Im Folgenden sehen Sie das Ergebnis mit dem Text, der der benannten Gruppe _catchall
zugewiesen ist.
"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."
Verwenden Sie als Erstes eine benannte Catchall-Gruppe, wenn Sie den Ausdruck erstellen
Beginnen Sie beim Erstellen einer Extraktionsanweisung mit einem Ausdruck, der mehr findet, als Sie möchten. Erweitern Sie dann den Ausdruck für ein Feld nach dem anderen.
Im folgenden Beispiel wird zuerst eine benannte Gruppe (_catchall
) verwendet, die mit der gesamten Nachricht übereinstimmt. Anschließend wird der Ausdruck schrittweise erstellt, indem zusätzliche Teile des Textes abgeglichen werden. Bei jedem Schritt enthält die benannte Gruppe _catchall
weniger des Originaltexts. Fahren Sie fort und wiederholen Sie Schritt für Schritt, um die Nachricht abzugleichen, bis Sie die benannte Gruppe _catchall
nicht mehr benötigen.
Schritt | Regulärer Ausdruck im Parsercode | Ausgabe der benannten Erfassungsgruppe _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\". |
Fahren Sie fort, bis der Ausdruck der gesamten Textzeichenfolge entspricht. |
Escape-Zeichen für Abkürzungen in regulären Ausdrücken
Denken Sie daran, Kurzzeichen für reguläre Ausdrücke zu maskieren, wenn Sie den Ausdruck im Parsercode verwenden. Im Folgenden finden Sie ein Beispiel für einen Textstring und den regulären regulären Ausdruck, mit dem das erste Wort This
extrahiert wird.
This is a sample log.
Der folgende reguläre reguläre Ausdruck extrahiert das erste Wort This
.
Wenn Sie diesen Ausdruck jedoch im Parsercode ausführen, fehlt im Ergebnis der Buchstabe s
.
Regulärer Standardausdruck | Ausgabe der benannten Erfassungsgruppe _firstWord |
---|---|
"^(?P<_firstWord>[^\s]+)\s.*$" |
"_firstWord": "Thi", |
Das liegt daran, dass reguläre Ausdrücke im Parsercode ein zusätzliches Escapezeichen erfordern, das den Kurzzeichen hinzugefügt wird. Im vorherigen Beispiel muss \s
in \\s
geändert werden.
Überarbeiteter regulärer Ausdruck für Parsercode | Ausgabe der benannten Erfassungsgruppe _firstWord |
---|---|
"^(?P<_firstWord>[^\\s]+)\\s.*$" |
"_firstWord": "This", |
Dies gilt nur für Kurzzeichen wie \s
, \r
und \t
.
Für andere Zeichen wie „“ müssen keine weiteren Escape-Zeichen verwendet werden.
Ein vollständiges Beispiel
In diesem Abschnitt werden die vorherigen Regeln als End-to-End-Beispiel beschrieben. Hier sehen Sie einen unstrukturierten Textstring und den regulären regulären Ausdruck, der zum Parsen des Strings geschrieben wurde. Schließlich enthält sie den geänderten regulären Ausdruck, der im Parsercode funktioniert.
Das ist die ursprüngliche Textzeichenfolge.
User "BOB" logged on to workstation "DESKTOP-01".
Im Folgenden finden Sie einen regulären RE2-Standardausdruck, der die Textzeichenfolge parst.
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
Mit diesem Ausdruck werden die folgenden Felder extrahiert.
Übereinstimmungsgruppe | Zeichenposition | Textstring |
---|---|---|
Vollständige Übereinstimmung | 0-53 | User \"BOB\" logged on to workstation \"DESKTOP-01\". |
Gruppe „_user“ | 7-10 | BOB |
Gruppe 2. | 13-22 | logged on |
Gruppe „_device“ | 40-50 | DESKTOP-01 |
Dies ist der geänderte Ausdruck. Der reguläre RE2-Standardausdruck wurde so geändert, dass er im Parsercode funktioniert.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$