データをクエリする際に正規表現を使用する

IBM Cloud Logs のデータをクエリする際、パターン検索や文字列置換のために正規表現(regex)を使用できます。

ログから特定のデータを抽出すると、分析や可視化が容易になる場合があります。 特定のログデータを取得したい場合もあるでしょう。 また、ログが保存される前に、機密データを隠す必要がある場合もあります。

また、正確なテキスト検索ではなく、正規表現パターンを使用して一致させることもできます。

正規表現とは何ですか?また、どのように機能するのですか?

正規表現(regex)は、パターン検索や置換に使用されるドメイン固有言語(DSL)です。

このトピックの情報は、正規表現に関する完全な教育的なチュートリアルを提供することを目的としたものではありません。 正規表現に不慣れな場合は、ここで説明する特定の概念を理解する前に、一般に公開されている正規表現に関する情報を確認することをお勧めします。

正規表現の概念

このトピックの例を理解するには、いくつかの基本的な概念を知っておく必要があります。

キャプチャグループ
括弧内に含まれる正規表現。 括弧内の指定に一致するテキストに演算子が適用されます。
名前付きキャプチャグループ
名前に関連付けられたキャプチャグループ。 一致した結果は、名前で参照できます
文字クラス
一致させる文字の範囲を角括弧で囲みます( [] )。ダッシュは、複数の文字を列挙する省略形として使用できます。 [1-5][12345] と同じです。

正規表現を使用するタイミング

正規表現は必要なく、特定のテキストを検索するだけでよい場合もあります。 例えば、 user logged in というテキストを含むログ行を見つけたいだけなら、このテキストをログ検索に入力するだけで済みます。 しかし、ログ行が次のような場合、 user_32 logged in ユーザーIDは変化する変数であるため、正確なテキストを検索することはできません。

幸い、このケースには、任意のシーケンスに一致する正規表現パターンがあります

user_d+ logged in

正規表現を使用して、カスタムJSONフィールドにテキストを抽出する

以下のような形式の構造化されていないログがあるとします

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

そして、この形式のすべてのエントリーを、以下の形式のJSONオブジェクトに変換したいと思います

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

この正規表現を使用して変換を行うことができます

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

ここで、

  • ^ 行頭記号である場合は、一致する文字列は行頭で始まる必要があることを意味します。
  • (?PX) X は一致するものであり、名前付きキャプチャグループ構文です。 この正規表現には、必要なJSONキーごとに3つのキャプチャグループがあります。
  • s 「任意の空白文字」を意味します。
  • . 「任意の1文字」を意味します。
  • * 「前の記号または文字に0回以上一致する」という意味です。
  • .* 「前の記号または文字に1つ以上の一致がある」という意味です。
  • .*? 「任意の文字を必要な最小限のトークン数で何度でも」という意味です。

つまり、正規表現は:

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

以下のように処理されます

  1. 行頭から始まり、最初の : 記号までのテキストは、グループ level として取得されます。

  2. 任意の数の空白文字の後、次の : 記号までのテキストはすべてグループ tag として取得されます。

  3. ログテキストは、 IBM Cloud Logs によって自動的に text フィールドに設定されるので、 text フィールドも自動的に作成されます。

同じ正規表現を使用すると、次のログが出力されます

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

このJSONオブジェクトに変換されます

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

テキストをあらかじめ定義されたフィールドに抽出する

テキストをあらかじめ設定したフィールドに抽出したい場合もあるでしょう。 このログを考えてみましょう

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

info のテキストを Severity の列に、 World のテキストを Class の列に抽出したいかもしれません。

正規表現を修正して、キャプチャグループの正しい名前を設定するには、次のようにします

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

この正規表現は、ログをフォーマットし、表示を以下のようにします。

整形されたログの表示例
正規表現による整形を適用した後のログ表示

構造化されたログから特定のデータを抽出する

同様の方法で、構造化されたログからデータを抽出することができます。 以下は、特定のJSONフィールドからデータを抽出する方法を示す例です。

以下のような構造化されたログ行があると仮定します

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

region フィールドが次の形式の場合:

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

その地域が europeasiana のどれに該当するかを教えてくれる部分を抽出したい。 データを抽出するための正規表現は次のようになります

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

regionName という名前のキャプチャグループが、テキストを抽出します。 地域名は、当社のフォーマットに従って、キー名 region と文字 rg- の後に続きます。 s* 記号の目的は、 : 記号の前後に空白文字がある場合でも、正規表現が機能し続けるようにすることです。

結果は次のようなものになります:

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

値の置換と削除

値を置き換えたり削除したりする必要がある最も一般的な例のひとつが、個人情報の非表示です。 電話番号をどこかに記録するが、 IBM Cloud Logs に保存したくないとします。

例えば、次のような構造化されていないログ行があるとします

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

この行から電話番号と名前を削除したい。 この正規表現は、「sending sms」で始まる行に一致します

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

+ シンボルと空白を避ける必要があります。なぜなら、 + は正規表現の構文において特別な意味を持つからです。 この意味は「直前の1文字以上」です。

d という記号は、任意の一桁の数字に一致します。 * の記号は「0文字以上の前の文字」を意味することを覚えておいてください。 つまり、+*d+ は、 + 記号(または記号なし)を先頭に付けることができる1つ以上の数字に一致します。

この正規表現は、前の正規表現に一致したテキストを、電話番号と名前を除いた同じテキストに置き換えます

sending sms to phone number * to user *

そして、上記のルールを適用した結果がこれです

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

構造化されたログのJSON値の置換

構造化ログ内のJSON値の置換は、非構造化ログ内の値の置換と類似しています。 JSON 文字列全体が 置換ルール の入力として使用されます。

以下のJSON構造を使用します

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

type フィールドの値を別の値に置き換える必要があるとします。 type フィールドの値を一致させる方法は次のとおりです

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

: 文字の前後に空白がある場合、正規表現が正しく機能していることを確認するために、 s* 記号が必要であることを覚えておいてください。

type フィールドのすべての値を newType に置き換える正規表現は次のとおりです

"type":"newType"

バックリファレンスを使用する

west-europe-2 という形式の文字列で、 europeeu に置き換える必要があるとします。 そして、 region フィールドだけでなく、その文字列が見つかったログの他の部分でも同様の処理が必要だとします。 このパターンに一致するものは、この正規表現で簡単にできます

.+?-europe-d+

しかし、以前の方法で弦を交換するのは、かなり難しいかもしれません。 これは、 europe テキストの前後に2つの文字列を挿入する必要があり、それらの文字列は変わる可能性があるためです。 これを行うには、まず文字列をキャプチャグループに取得する必要があります

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

d の記号は「任意の数字」を意味し、 + と併せて「任意の数字が1回以上」を意味することを覚えておいてください。 同様に、 .+ は1つ以上の任意の記号を意味しますが、一致させるのに必要なトークンは最小限です。

この正規表現は、 europe の前のテキストをキャプチャグループ1として、 europe の後のテキストをキャプチャグループ2として取得します。 以下の正規表現では、バックリファレンスを使用して、それらのグループに一致した内容を挿入します

$1-eu-$2

例えば、当社のルールを適用する前のログ:

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

そして、ルール適用後のログ:

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

正規表現によるアラートのトリガー

IBM Cloud Logs における正規表現のもう一つの一般的な使用例は、アラートの定義です。アラートの構文はログのクエリ構文と同じです。

例えば、次のような形式の行について、私たちに通知したいとします

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

そして、 w-1w-2w-3w-4 の世界のみにアラートを設定したいとします。 私たちの警告用正規表現は次のようになります

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

[1-4]1 から 4 までの任意の一文字に一致し、 .* は任意の文字を任意の回数一致します。

アラートに関する詳細情報については、以下をご覧ください