Verwendung von Regex bei der Abfrage von Daten

Bei der Abfrage von IBM Cloud Logs-Daten können Sie reguläre Ausdrücke (Regex) zur Mustersuche und zum Ersetzen von Zeichenfolgen verwenden.

Sie können bestimmte Daten aus Ihren Protokollen extrahieren, um die Analyse und Visualisierung zu erleichtern. Manchmal möchten Sie vielleicht bestimmte protokollierte Daten erfassen. In anderen Fällen müssen Sie möglicherweise sensible Daten in Protokollen verbergen, bevor sie gespeichert werden.

Sie können auch mit einem Regex-Muster statt einer exakten Textsuche suchen.

Was ist regex und wie funktioniert es?

Reguläre Ausdrücke, auch als Regex bekannt, sind eine domänenspezifische Sprache (DSL), die für Mustersuchen und Ersetzungen verwendet wird.

Die Informationen in diesem Thema sind nicht als vollständige Anleitung zu Regex gedacht. Wenn Sie mit Regex nicht vertraut sind, sollten Sie sich öffentlich zugängliche Informationen zu Regex ansehen, bevor Sie versuchen, die hier enthaltenen spezifischen Konzepte zu verstehen.

Regex-Konzepte

Es gibt einige grundlegende Konzepte, die Sie kennen müssen, um die Beispiele in diesem Thema zu verstehen.

Erfassungsgruppe
Regex in Klammern. Die Operatoren werden auf den Text angewendet, der der Spezifikation in der Klammer entspricht.
Benannte Erfassungsgruppe
Eine Erfassungsgruppe, die mit einem Namen verknüpft ist. Die übereinstimmenden Ergebnisse können über den Namen aufgerufen werden
Charakterklasse
Eine Reihe von Zeichen, die abgeglichen werden sollen, wird in eckige Klammern gesetzt ( [] ). Ein Bindestrich kann als Abkürzung verwendet werden, um mehrere Zeichen aufzulisten: [1-5] ist dasselbe wie [12345].

Wann sollte man Regex verwenden?

Manchmal benötigen Sie keinen regulären Ausdruck und können einfach nach einem bestimmten Text suchen. Wenn Sie beispielsweise nur nach Logzeilen mit dem Text user logged in suchen möchten, können Sie diesen Text einfach in Ihre Logsuche eingeben. Wenn Ihre Log-Zeilen jedoch so aussehen: user_32 logged in, können Sie nicht nach dem genauen Text suchen, da die Benutzer-ID eine Variable ist, die sich ändert.

Glücklicherweise gibt es für diesen Fall ein Regex-Muster, das die Sequenz "match anything" verwendet:

user_d+ logged in

Verwendung von Regex, um Text in benutzerdefinierte JSON-Felder zu extrahieren

Angenommen, Sie haben ein unstrukturiertes Protokoll im folgenden Format:

${logLevel}: World-${worldName}: ${logText}

Und Sie möchten alle Einträge in diesem Format in ein JSON-Objekt im folgenden Format umwandeln:

{
    "level": `${log-level}`,
    "tag": `World-${worldName}`,
    "text": `${logText}`
}

Sie können diesen regulären Ausdruck verwenden, um die Konvertierung durchzuführen:

^(?P.*?):s*(?P.*?):

Dabei gilt:

  • ^ ist das Symbol für den Zeilenanfang, d. h., die Übereinstimmung muss mit dem Zeilenanfang beginnen.
  • (?PX) wobei X das übereinstimmende Element ist und die benannte Erfassungsgruppensyntax ist. Diese Regex hat drei Erfassungsgruppen, eine für jeden benötigten JSON-Schlüssel.
  • s bedeutet "jedes Leerzeichen".
  • . bedeutet "ein beliebiges Zeichen".
  • * bedeutet "0 oder mehr Übereinstimmungen mit dem vorherigen Symbol oder Zeichen".
  • .* bedeutet "1 oder mehrere Übereinstimmungen des vorherigen Symbols oder Zeichens".
  • .*? bedeutet "beliebige Zeichen beliebig oft mit der geringstmöglichen Anzahl an Token".

Also, die Regex:

^(?P.*?):s*(?P.*?):

Wird wie folgt bearbeitet:

  1. Text, der am Anfang einer Zeile beginnt, bis zum ersten :-Symbol wird als Gruppe level erfasst.

  2. Nach einer beliebigen Anzahl von Leerzeichen wird jeder Text bis zum nächsten :-Symbol als Gruppe tag erfasst.

  3. Der Logtext wird automatisch von IBM Cloud Logs in das Feld text gesetzt, sodass wir automatisch das Feld text haben.

Mit demselben regulären Ausdruck wird das folgende Protokoll erstellt:

"info: World-w-8: generate: new world"

Wird in dieses JSON-Objekt umgewandelt:

{
   "level": "info",
   "tag": "World-w-8",
   "text": "info: World-w-8: generate: new world"
}

Extrahieren von Text in vordefinierte Felder

Sie können Text in vordefinierte Felder extrahieren. Betrachten Sie dieses Protokoll:

"info: World-w-8: generate: new world"

Sie können den Text von info in die Spalte Severity und den Text von World in die Spalte Class extrahieren.

Sie können die Regex wie folgt ändern, um die korrekten Namen der Erfassungsgruppen festzulegen:

^(?P.*?):s*(?P.*?)-(?P.*?):

Diese Regex formatiert das Protokoll so, dass es wie abgebildet angezeigt wird.

Beispielansicht mit formatiertem Protokoll
Protokollanzeige nach Anwendung der Regex-Formatierung

Extrahieren spezifischer Daten aus strukturierten Protokollen

Eine ähnliche Methode kann verwendet werden, um Daten aus strukturierten Protokollen zu extrahieren. Im Folgenden wird anhand eines Beispiels gezeigt, wie Daten aus einem bestimmten JSON-Feld extrahiert werden.

Angenommen, Sie haben eine strukturierte Log-Zeile, die dieser ähnelt:

{
    "type": `${text}`,
    "log": `${text}`,
    "region": "rg-europe-2"
}

Wenn das Feld region nun die folgende Form hat:

`rg-${"europe"|"asia"|"na"}-${number}`

Wir wollen den Teil extrahieren, der uns sagt, ob die Region europe, asia oder na ist. Die Regex zum Extrahieren der Daten wäre:

"region"s*:s*"rg-(?P.*?)-

Die benannte Erfassungsgruppe regionName extrahiert den Text. Der Name der Region ist nach dem Schlüsselnamen region und den Zeichen rg- gemäß unserem Format benannt. Der Zweck der s*-Symbole besteht darin, dass regex auch dann noch funktioniert, wenn vor oder nach dem :-Symbol Leerzeichen stehen.

Das Ergebnis wird in etwa wie folgt aussehen:

{
    "log" : "Bye",
    "regionName" : "na",
    "region" : "rg-na-1",
    "type" : "ltest-w-9"
}

Werte ersetzen und entfernen

Eines der häufigsten Beispiele, bei denen wir Werte ersetzen oder entfernen müssen, ist das Verbergen persönlicher Daten. Angenommen, Sie haben Telefonnummern irgendwo notiert und möchten nicht, dass diese in IBM Cloud Logs gespeichert werden.

Nehmen wir an, wir haben eine unstrukturierte Log-Zeile wie diese:

"info: Sender: sendSms: sending sms to phone number +12345678910 to user Andrew"

Sie möchten die Telefonnummer und den Namen aus dieser Zeile entfernen. Diese Regex wird mit der Zeile übereinstimmen, die mit "sending sms" beginnt:

sending sms to phone number +*d+ to user .*

Wir müssen das +-Symbol durch ein Leerzeichen ersetzen, da + in der Regex-Syntax eine besondere Bedeutung hat. Diese Bedeutung ist "1 oder mehrere vorherige Zeichen".

Das Symbol d passt zu jeder einzelnen Ziffer. Denken Sie daran, dass das Symbol * "0 oder mehr vorherige Zeichen" bedeutet. Also entspricht +*d+ einer oder mehreren Ziffern, denen ein +-Symbol vorangestellt werden kann (oder auch nicht).

Diese Regex ersetzt den Text, der mit der vorherigen Regex übereinstimmt, durch denselben Text, jedoch ohne die Telefonnummer und den Namen:

sending sms to phone number * to user *

Und hier ist das Ergebnis der Anwendung der obigen Regel:

"info: Sender: sendSms: sending sms to phone number * to user *"

Ersetzen von JSON-Werten in strukturierten Protokollen

Das Ersetzen von JSON-Werten in strukturierten Protokollen ähnelt dem Ersetzen von Werten in unstrukturierten Protokollen. Der gesamte JSON-String wird als Eingabe für die Ersetzungsregel verwendet.

Verwenden Sie die folgende JSON-Struktur:

{
   "type": `${text}`,
   "log": `${text}`,
   "region": "rg-europe-2"
}

Angenommen, Sie müssen den Wert des Feldes type durch einen anderen Wert ersetzen. So können Sie den Wert des Feldes type abgleichen:

"type"s*:s*".*?"

Denken Sie daran, dass wir die s*-Symbole benötigen, um sicherzustellen, dass die Regex funktioniert, wenn vor oder nach dem :-Zeichen Leerzeichen stehen.

Hier ist der Regex, um jeden Wert im Feld type durch newType zu ersetzen:

"type":"newType"

Verwendung von Rückverweisen

Angenommen, wir müssen europe durch eu in den Zeichenketten im Format west-europe-2 ersetzen. Und nehmen wir an, wir müssen dies nicht nur im Feld region tun, sondern in jedem anderen Teil des Protokolls, in dem die Zeichenfolge gefunden wird. Dieses Muster lässt sich mit diesem regulären Ausdruck leicht abgleichen:

.+?-europe-d+

Allerdings könnte es ziemlich schwierig sein, die Saite mit den Methoden zu ersetzen, die wir zuvor verwendet haben. Das liegt daran, dass wir vor und nach dem Text europe zwei Zeichenfolgen einfügen müssen, die variieren können. Dazu müssen wir zunächst die Strings in Erfassungsgruppen erfassen:

(.+?)-europe-(d+)

Denken Sie daran, dass das Symbol d "eine beliebige Ziffer" bedeutet und zusammen mit + "eine beliebige Ziffer ein- oder mehrmals". In ähnlicher Weise bedeutet .+ ein oder mehrere Symbole, aber mit der geringsten Anzahl an Token, um die Übereinstimmung zu erzielen.

Diese Regex erfasst den Text vor europe als Erfassungsgruppe 1 und den Text nach europe als Erfassungsgruppe 2. Der folgende reguläre Ausdruck verwendet Rückverweise, um den übereinstimmenden Inhalt dieser Gruppen einzufügen:

$1-eu-$2

Zum Beispiel ein Protokoll vor der Anwendung unserer Regel:

{
    "log" : "Here region is east-europe-1. That's it",
    "type" : "newType",
    "region" : "east-europe-1"
}

Und das Protokoll nach Anwendung der Regel:

{
    "log" : "Here region is east-eu-1. That's it",
    "type" : "newType",
    "region" : "east-eu-1"
}

Auslösen von Warnungen mit Regex

Ein weiterer beliebter Anwendungsfall für Regex in IBM Cloud Logs ist die Definition von Warnmeldungen. Die Syntax für Warnmeldungen ist dieselbe wie die Syntax für Protokollabfragen.

Nehmen wir an, wir möchten uns über eine Zeile der folgenden Form benachrichtigen lassen:

`App: init: World-${name}: generation error: ${err}`

Und nehmen wir an, wir möchten nur Benachrichtigungen für die Welten w-1, w-2, w-3 oder w-4 erhalten. Unser Regex-Alarm sieht dann so aus:

/text.keyword:/.*World-w-[1-4]: generation error.*//

Denken Sie daran, dass [1-4] mit jedem einzelnen Zeichen von 1 bis 4 übereinstimmt und .* mit jedem beliebigen Zeichen beliebig oft übereinstimmt.

Weitere Informationen zu Warnmeldungen finden Sie unter: