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- oder replace-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 Wert USER_LOGIN hat und das UDM-Feld target.user value nicht festgelegt ist.
  • Wenn metadata.event_type den Wert NETWORK_CONNECTION hat und das UDM-Feld target.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>[^\\\\]+)\\\"\\.$