查詢資料時使用 regex

在查詢 IBM Cloud Logs 資料時,您可以使用正規表達式(regex)進行模式搜尋和字串替換。

您可能想要從日誌中擷取特定資料,使其更容易分析及視覺化。 有時您可能想要擷取特定的記錄資料。 其他時候,您可能需要在儲存日誌之前,將敏感資料隱藏在日誌中。

您也可以使用 regex 模式而非精確的文字搜尋來進行匹配。

什麼是正規表達式?它是如何運作的?

正規表達式 (Regular Expressions) 也稱為 regex,是一種特定領域語言 (DSL),用於模式搜尋和取代。

本主題中的資訊並不打算提供完整的 regex 教育教學。 如果您不熟悉 regex,在嘗試理解此處包含的特定概念之前,您可能需要檢閱有關 regex 的公開資訊。

Regex 概念

要了解本主題中的範例,您需要知道一些基本概念。

擷取群組
括號中包含 Regex。 運算符號適用於括號內符合規格的文字。
命名擷取群組
與名稱相關聯的擷取群組。 匹配的結果可以用以下名稱參照
角色類別
方括號內 ( [] ) 所括的要匹配的字元範圍。破折號可用來作為列出數個字元的速記:[1-5][12345] 相同。

何時使用 regex

有時您不需要正則表達式,只需搜尋特定文字即可。 例如,如果您只想尋找包含文字 user logged in 的日誌行,您只需在日誌搜尋中輸入此文字即可。 但如果您的日誌行如下所示:user_32 logged in,您就無法搜尋準確的文字,因為使用者 ID 是會改變的變數。

幸運的是,有一個 regex 模式可以使用 match anything 序列來處理這種情況:

user_d+ logged in

使用 regex 將文字擷取至自訂 JSON 欄位

假設您有以下格式的非結構化日誌:

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

而且,您希望將此格式的所有條目轉換成以下格式的 JSON 物件:

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

您可以使用此 regex 進行轉換:

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

其中:

  • ^ 是行的開始符號,表示匹配需要從行的開始開始。
  • (?PX) 其中 是要匹配的內容,並且是已命名的擷取群組語法。X 這個 regex 有三個捕捉群組,每個 JSON key 需要一個。
  • s 表示「任何空白字元」。
  • . 表示「任何一個字元」。
  • * 表示「前一個符號或字元有 0 個或更多匹配項目」。
  • .* 表示「有 1 個或更多前一個符號或字元符合」。
  • .*? 表示「任何字元的任何次數,所需的代幣量最少」。

因此,regex:

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

將按以下方式處理:

  1. 從一行的開始到第一個 : 符號的文字將被擷取為群組 level

  2. 在任意數量的空白符號之後,直到下一個 : 符號之前的任何文字都將擷取為群組 tag

  3. 日誌文字會由 IBM Cloud Logs 自動設定為 text 欄位,因此我們會自動擁有 text 欄位。

使用相同的 regex,可得到以下日誌:

"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 欄。

您可以修改 regex 以設定正確的擷取群組名稱,如下所示:

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

此 regex 將格式化日誌,使其顯示如圖所示。

顯示格式化記錄的檢視範例
套用 regex 格式化後的記錄顯示

從結構化日誌擷取特定資料

類似的方法可用於從結構化日誌中擷取資料。 以下是一個範例,說明如何從特定的 JSON 欄位擷取資料。

假設您有類似的結構化日誌行:

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

現在,如果 region 欄位的形式如下:

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

我們要擷取的部分是要告訴我們這個區域是 europe, asiana。 擷取資料的 regex 應該是:

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

命名的擷取群組 regionName 就是擷取文字的方法。 根據我們的格式,區域名稱在關鍵名稱 region 之後,字元 rg-s* 符號的目的是讓 regex 在 : 符號之前或之後有任何空白的情況下仍能運作。

結果將類似於以下內容:

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

您要從這一行移除電話號碼和姓名。 此 regex 將配對以 "sending sms" 開頭的一行:

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

我們需要將 + 符號轉換為空格,因為 + 在 regex 語法中有特殊意義。 此義為「1 個或更多先前的字元」。

符號 d 可匹配任何單一數字。 請記住,* 符號表示「0 或更多前一個字元」。 因此,+*d+ 會匹配一個或多個數字,這些數字可以以 + 符號作為前綴(也可以不)。

此 regex 將取代前一個 regex 匹配的文字為相同的文字,但不包含電話號碼和姓名:

sending sms to phone number * to user *

以下是應用上述規則的結果:

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

取代結構化日誌中的 JSON 值

取代結構化日誌中的 JSON 值與取代非結構化日誌中的值類似。 整個 JSON 字串會用作 Replace 規則 的輸入。

使用下列 JSON 結構:

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

假設您需要使用其他值取代 type 欄位的值。 以下是如何匹配 type 欄位的值:

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

請記住,我們需要 s* 符號,以確保在 : 字元之前或之後有空白符號時,regex 可以正常運作。

以下是用 newType 取代 type 欄位中任何值的 regex:

"type":"newType"

使用反向參考

假設我們需要在格式 west-europe-2 的字串中以 eu 取代 europe。 假設我們不只需要在 region 欄位,也需要在日誌中找到字串的任何其他部分執行這項工作。 使用此 regex 即可輕鬆匹配此模式:

.+?-europe-d+

不過,使用我們之前使用的方法來取代字串可能比較困難。 這是因為我們需要在 europe 文字之前和之後插入兩個字串,而這些字串可能會有所不同。 要做到這一點,我們首先需要將字串擷取到擷取群組中:

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

請記住 d 符號的意思是「任何數字」,與 + 一起的意思是「任何數字的一次或多次」。 與此類似,.+ 表示任何符號出現一次或多次,但以最少的代幣數進行匹配。

此 regex 將擷取 europe 之前的文字為擷取群組 1,而 europe 之後的文字為擷取群組 2。 以下 regex 將使用反向參考插入這些群組的匹配內容:

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

使用 regex 觸發警示

IBM Cloud Logs 中 regex 的另一個常用情況是定義警報。警報語法與日誌查詢語法相同。

比方說,我們希望在以下形式的行中提醒我們:

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

假設我們只想取得世界 w-1, w-2, w-3w-4 的警示。 我們的警示重組將如下所示:

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

請記住,[1-4] 會匹配從 14 的任何單一字元,而 .* 會匹配任何字元的任何次數。

有關警示的更多資訊,請參閱: