Tipps und Fehlerbehebung beim Schreiben von Parsern

Unterstützt in:

In diesem Dokument werden Probleme beschrieben, die beim Schreiben von Parsercode auftreten können.

Beim Schreiben von Parsercode können Fehler auftreten, wenn das Parsen von Anweisungen nicht wie erwartet funktioniert. In folgenden Situationen können Fehler auftreten:

  • Ein Grok-Muster schlägt fehl
  • Ein rename- oder replace-Vorgang schlägt fehl
  • Syntaxfehler im Parsercode

Gängige Praktiken im Parsercode

In den folgenden Abschnitten werden Best Practices, Tipps und Lösungen zur Fehlerbehebung beschrieben.

Punkte oder Bindestriche in Variablennamen vermeiden

Die Verwendung von Bindestrichen und Punkten in Variablennamen kann zu unerwartetem Verhalten führen, insbesondere bei merge-Vorgängen zum Speichern von Werten in UDM-Feldern. Es kann auch zu vorübergehenden Parsing-Problemen kommen.

Verwenden Sie beispielsweise nicht die folgenden Variablennamen:

  • my.variable.result
  • my-variable-result

Verwenden Sie stattdessen den folgenden Variablennamen: my_variable_result.

Verwenden Sie keine Begriffe mit besonderer Bedeutung als Variablennamen.

Bestimmte Wörter wie event und timestamp können im Parsercode eine besondere Bedeutung haben.

Der String event wird häufig verwendet, um einen einzelnen UDM-Datensatz darzustellen, und wird in der @output-Anweisung verwendet. Wenn eine Log-Nachricht ein Feld namens event enthält oder Sie eine Zwischenvariable namens event definieren und im Parsercode das Wort event in der @output-Anweisung verwendet wird, 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 Rohlogs. Ein in dieser Zwischenvariablen festgelegter Wert wird im UDM-Feld metadata.event_timestamp gespeichert. Der Begriff @timestamp steht für das Datum und die Uhrzeit, zu der das Rohlog geparst wurde, um einen UDM-Datensatz zu erstellen.

Im folgenden Beispiel wird das UDM-Feld metadata.event_timestamp auf das Datum und die Uhrzeit festgelegt, zu der das Rohlog geparst wurde.

 # Save the log parse date and time to the timestamp variable
  mutate {
     rename => {
       "@timestamp" => "timestamp"
     }
   }

Im folgenden Beispiel wird das UDM-Feld metadata.event_timestamp auf das Datum und die Uhrzeit festgelegt, die aus dem ursprünglichen Rohlog extrahiert und in der Zwischenvariablen when gespeichert wurden.

   # Save the event timestamp to timestamp variable
   mutate {
     rename => {
       "when" => "timestamp"
     }
   }

Verwenden Sie die folgenden Begriffe nicht als Variablen:

  • collectiontimestamp
  • createtimestamp
  • event
  • filename
  • Nachricht
  • Namespace
  • Ausgabe
  • onerrorcount
  • timestamp
  • Zeitzone

Jeden Datenwert in einem separaten UDM-Feld speichern

Speichern Sie nicht mehrere Felder in einem einzelnen 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

Verwenden Sie im Parsercode keine Tabulatoren. Verwenden Sie nur Leerzeichen und rücken Sie jeweils um zwei Leerzeichen ein.

Führen Sie nicht mehrere Zusammenführungen in einem einzigen Vorgang durch.

Wenn Sie mehrere Felder in einem einzigen Vorgang zusammenführen, kann dies zu inkonsistenten Ergebnissen führen. Platzieren Sie merge-Anweisungen stattdessen in separaten Vorgängen.

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"
  }
}

if- und if else-bedingte Ausdrücke

Wenn der bedingte Wert, den Sie testen, immer nur eine Übereinstimmung haben kann, verwenden Sie die if else-Bedingungsanweisung. Dieser Ansatz ist etwas effizienter. Wenn der getestete Wert jedoch mehrmals übereinstimmen könnte, verwenden Sie mehrere unterschiedliche if-Anweisungen und ordnen Sie die Anweisungen vom allgemeinsten zum spezifischsten Fall.

Repräsentative Gruppe von Logdateien zum Testen von Parseränderungen auswählen

Es empfiehlt sich, Parsercode mit Rohlog-Beispielen in einer Vielzahl von Formaten zu testen. So können Sie eindeutige Logs oder Grenzfälle finden, die der Parser möglicherweise verarbeiten muss.

Dem Parsercode beschreibende Kommentare hinzufügen

Fügen Sie dem Parsercode Kommentare hinzu, in denen erklärt wird, warum die Anweisung wichtig ist, und nicht, was die Anweisung bewirkt. Der Kommentar hilft allen, die den Parser verwalten, den Ablauf nachzuvollziehen. 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, initialisieren Sie Zwischenvariablen, in denen Testwerte gespeichert werden.

So wird verhindert, dass ein Fehler zurückgegeben wird, der darauf hinweist, dass die Zwischenvariable nicht vorhanden ist.

Mit der folgenden Anweisung wird der Wert 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, erhalten Sie die folgende Fehlermeldung:

"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 einer booleschen Zwischenvariablen mit dem Namen _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"
}

Im vorherigen Beispiel wird der folgende Fehler zurückgegeben, 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"

Fügen Sie dazu einen separaten Anweisungsblock hinzu, in dem die Zwischenvariablen initialisiert werden, bevor die Anweisungen für den Extraktionsfilter (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 Snippet des Parsercodes verarbeitet die verschiedenen Szenarien mithilfe einer bedingten Anweisung, um zu prüfen, ob das Feld vorhanden ist. Außerdem werden mit der on_error-Anweisung Fehler behandelt, die auftreten können.

SHA-256 in Base64 konvertieren

Im folgenden Beispiel wird der SHA‑256-Wert extrahiert, in Base64 codiert, in einen hexadezimalen String konvertiert und dann werden 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 schlecht formatierte Daten enthalten.

Sie können den Parser so erstellen, dass er diese Fehler verarbeitet. Als Best Practice wird empfohlen, on_error-Handler zum Extraktionsfilter hinzuzufügen und dann die Zwischenvariable zu testen, bevor Sie mit dem nächsten Segment der Parserlogik fortfahren.

Im folgenden Beispiel wird der json-Extraktionsfilter mit einer on_error-Anweisung verwendet, um die boolesche Variable _not_json festzulegen. Wenn _not_json auf true gesetzt ist, bedeutet das, dass der eingehende Logeintrag kein gültiges JSON-Format hatte und nicht erfolgreich geparst wurde. Wenn die Variable _not_json den Wert false hat, war der eingehende Logeintrag in einem gültigen 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. Das bedeutet, 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 die Verarbeitung nicht fehlschlägt, wenn Logs mit einem falschen Format für den angegebenen Logtyp erfasst werden.

Verwenden Sie den drop-Filter 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 drop-Filter verhindert, dass der Parser das Rohlog verarbeitet, die Felder normalisiert und einen UDM-Datensatz erstellt. Das ursprüngliche Rohlog wird weiterhin in Google Security Operations aufgenommen und kann dort über die Rohlog-Suche durchsucht werden.

Der an die Variable tag übergebene Wert wird in der Tabelle „Aufnahmemesswerte“ im Feld drop_reason_code gespeichert. Sie können eine Ad-hoc-Abfrage für die Tabelle ausführen, die der folgenden ähnelt:

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 Validierungsfehler auftreten, z. B. wenn ein Pflichtfeld im UDM-Datensatz nicht festgelegt ist. Der Fehler sieht in etwa so aus:

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, aber der generierte UDM-Datensatz enthält nicht alle erforderlichen UDM-Felder, die durch den auf metadata.event_type festgelegten Wert definiert sind. Hier sind weitere Beispiele, die diesen Fehler verursachen können:

  • Wenn metadata.event_type USER_LOGIN ist und das UDM-Feld target.user value nicht festgelegt ist.
  • Wenn metadata.event_type NETWORK_CONNECTION ist und das UDM-Feld target.hostname nicht festgelegt ist.

Weitere Informationen zum UDM-Feld metadata.event_type und zu erforderlichen Feldern finden Sie im UDM-Leitfaden.

Eine Möglichkeit zur Fehlerbehebung bei dieser Art von Fehler besteht darin, zuerst statische Werte für UDM-Felder festzulegen. Nachdem Sie alle erforderlichen UDM-Felder definiert haben, sehen Sie sich das ursprüngliche Rohlog an, um zu ermitteln, welche Werte geparst und im UDM-Datensatz gespeichert werden sollen. Wenn das ursprüngliche Rohlog bestimmte Felder nicht enthält, müssen Sie möglicherweise Standardwerte festlegen.

Im Folgenden finden Sie eine Beispielvorlage, die speziell für den Ereignistyp USER_LOGIN entwickelt wurde und diesen Ansatz veranschaulicht.

Beachten Sie Folgendes:

  • In der Vorlage werden Zwischenvariablen initialisiert und jeweils auf einen statischen String festgelegt.
  • Mit dem Code im Abschnitt Feldzuweisung werden die Werte in Zwischenvariablen auf UDM-Felder festgelegt.

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 Eingabekonfiguration Code hinzu, mit dem Felder aus dem ursprünglichen Rohlog extrahiert und die Werte für die Zwischenvariablen festgelegt werden.

  • Fügen Sie im Abschnitt Datum extrahieren Code hinzu, mit dem der Ereignis-Zeitstempel aus dem ursprünglichen Rohlog extrahiert, transformiert und auf die Zwischenvariable festgelegt wird.

  • 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 eine Grok-Funktion verwenden, um Werte aus unstrukturiertem Text zu extrahieren, können Sie vordefinierte Grok-Muster und reguläre Ausdrücke verwenden. Grok-Muster machen Code leichter lesbar. Wenn der reguläre Ausdruck keine Kurzzeichen wie \w oder \s enthält, können Sie die Anweisung direkt in den Parsercode kopieren und einfügen.

Da Grok-Muster eine zusätzliche Abstraktionsebene in der Anweisung darstellen, kann die Fehlerbehebung komplexer sein, wenn ein Fehler auftritt. Das Folgende ist ein Beispiel für 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 beispielsweise weniger als die Hälfte der Verarbeitungsschritte erforderlich, um eine Übereinstimmung zu finden. Bei einer potenziell umfangreichen Protokollquelle ist dies ein wichtiger Aspekt.

Unterschiede zwischen regulären RE2- und PCRE-Ausdrücken

Google SecOps-Parser verwenden RE2 als Engine für reguläre Ausdrücke. Wenn Sie mit der PCRE-Syntax vertraut sind, werden Ihnen möglicherweise Unterschiede auffallen. Hier ein Beispiel:

Das ist eine PCRE-Anweisung: (?<_custom_field>\w+)\s

Das Folgende ist eine RE2-Anweisung für Parsercode: (?P<_custom_field>\\w+)\\s

Escapezeichen müssen mit Escapezeichen versehen werden

Google SecOps speichert eingehende Rohprotokolldaten im JSON-codierten Format. So wird sichergestellt, dass Zeichenfolgen, die wie eine Kurzform für reguläre Ausdrücke aussehen, als Literalstring interpretiert werden. Beispiel: \t wird als Literalstring und nicht als Tabulatorzeichen interpretiert.

Das folgende Beispiel zeigt ein ursprüngliches Rohlog und das JSON-codierte Formatlog. Achten Sie auf das Escapezeichen, das vor jedem umgekehrten Schrägstrich um den Begriff entry herum eingefügt wurde.

Das ist das ursprüngliche unformatierte Log:

field=\entry\

Im Folgenden sehen Sie das in das JSON-codierte Format konvertierte Log:

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. Wenn Sie einen umgekehrten Schrägstrich im ursprünglichen Rohlog abgleichen möchten, verwenden Sie vier umgekehrte Schrägstriche in der Extraktionsanweisung.

Hier ist ein regulärer Ausdruck für Parsercode:

^field=\\\\(?P<_value>.*)\\\\$

Das ist das generierte Ergebnis. In der Gruppe mit dem Namen _value wird der Begriff entry gespeichert:

"_value": "entry"

Wenn Sie eine Standardanweisung für reguläre Ausdrücke in den Parsercode verschieben, müssen Sie die Kurzzeichen für reguläre Ausdrücke in der Extraktionsanweisung maskieren. Ändern Sie beispielsweise \s in \\s.

Lassen Sie Sonderzeichen für reguläre Ausdrücke unverändert, wenn sie in der Anweisung zum Extrahieren doppelt maskiert werden. Beispiel: \\ bleibt unverändert als \\.

Hier ist ein Standardbeispiel für einen 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 Escapezeichen enthalten muss, bevor er in Parsercode aufgenommen wird.

Regulärer Ausdruck Geänderter regulärer Ausdruck für Parsercode Beschreibung der Änderung
\s
\\s
Kürzel müssen mit Escapezeichen versehen werden.
\.
\\.
Reservierte Zeichen müssen mit Escapezeichen versehen werden.
\\"
\\\"
Reservierte Zeichen müssen mit Escapezeichen versehen werden.
\]
\\]
Reservierte Zeichen müssen mit Escapezeichen versehen werden.
\|
\\|
Reservierte Zeichen müssen mit Escapezeichen versehen werden.
[^\\]+
[^\\\\]+
Sonderzeichen in einer Zeichenklassengruppe müssen maskiert werden.
\\\\
\\\\
Für Sonderzeichen außerhalb einer Zeichenklassengruppe oder für Kurzzeichen ist kein zusätzliches 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 der Vorgang jedoch mit folgendem 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 reguläre Ausdrücke zum Überschreiben verwenden, müssen Sie eine benannte Gruppe einfügen.

Hier ist ein Beispiel für einen regulären Ausdruck im Parsercode:

"^(?P<_catchall>.*$)"

Das ist das Ergebnis mit dem Text, der der benannten Gruppe _catchall zugewiesen ist.

"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."

Verwenden Sie eine Auffanggruppe, um mit dem Erstellen des Ausdrucks zu beginnen.

Beginnen Sie beim Erstellen einer Extraktionsanweisung mit einem Ausdruck, der mehr erfasst, als Sie möchten. Erweitern Sie dann den Ausdruck Feld für Feld.

Im folgenden Beispiel wird zuerst eine benannte Gruppe (_catchall) verwendet, die der gesamten Nachricht entspricht. Anschließend wird der Ausdruck schrittweise erstellt, indem zusätzliche Teile des Texts abgeglichen werden. Mit jedem Schritt enthält die benannte Gruppe _catchall weniger vom Originaltext. Fahren Sie Schritt für Schritt fort, bis die Nachricht der gewünschten entspricht und 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 mit dem gesamten Textstring übereinstimmt.

Kürzelzeichen im regulären Ausdruck maskieren

Denken Sie daran, die Kurzzeichen für reguläre Ausdrücke zu maskieren, wenn Sie den Ausdruck im Parsercode verwenden. Im Folgenden sehen Sie ein Beispiel für einen Textstring und den Standard-Regulären Ausdruck, mit dem das erste Wort, This, extrahiert wird.

  This is a sample log.

Mit dem folgenden Standard-Regulären Ausdruck wird das erste Wort, This, extrahiert. Wenn Sie diesen Ausdruck jedoch in Parsercode ausführen, fehlt im Ergebnis der Buchstabe s.

Standardmäßiger regulärer Ausdruck Ausgabe der benannten Erfassungsgruppe _firstWord
"^(?P<_firstWord>[^\s]+)\s.*$" "_firstWord": "Thi",

Das liegt daran, dass für reguläre Ausdrücke im Parsercode ein zusätzliches Escapezeichen für die Kurzzeichen erforderlich ist. 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",

Das gilt nur für die Abkürzungen für Zeichenklassen wie \s, \r und \t. Andere Zeichen wie „“ müssen nicht weiter maskiert werden.

Vollständiges Beispiel

In diesem Abschnitt werden die vorherigen Regeln als End-to-End-Beispiel beschrieben. Hier sehen Sie einen unstrukturierten Textstring und den standardmäßigen regulären Ausdruck, der zum Parsen des Strings geschrieben wurde. Außerdem ist der geänderte reguläre Ausdruck enthalten, der im Parsercode funktioniert.

Im Folgenden finden Sie die ursprüngliche Textstring.

User "BOB" logged on to workstation "DESKTOP-01".

Im Folgenden sehen Sie einen standardmäßigen regulären RE2-Ausdruck, mit dem der Textstring analysiert wird.

^.*?\\\"(?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

Das 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>[^\\\\]+)\\\"\\.$

Benötigen Sie weitere Hilfe? Antworten von Community-Mitgliedern und Google SecOps-Experten erhalten