查询数据时使用正则表达式

在查询 IBM Cloud Logs 数据时,您可以使用正则表达式(regex)进行模式搜索和字符串替换。

您可能希望从日志中提取特定数据,以便更轻松地进行分析和可视化。 有时您可能想记录特定的数据。 有时,您可能需要在日志中隐藏敏感数据,然后再保存。

您也可以使用正则表达式模式进行匹配,而不是精确文本搜索。

什么是正则表达式?它是如何工作的?

正则表达式(Regular Expressions)也称为正则表达式(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键。
  • s 表示“任何空白字符”。
  • . 的意思是“任何一个字符”。
  • * 表示“与之前符号或字符匹配0次或多次”。
  • .* 表示“上一个符号或字符匹配1次或多次”。
  • .*? 的意思是“任意字符任意次数,所需代币最少”。

因此,正则表达式:

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

将按以下方式处理:

  1. 从行首到第一个 : 符号之间的文本将被视为 level 组。

  2. 在任意数量的空白字符后,直到下一个 : 符号之前的任何文本都将被捕获为 tag 组。

  3. 日志文本会自动设置为 text 字段,IBM Cloud Logs,因此我们将自动拥有 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}`

我们想提取出告诉我们该地区是 europeasia 还是 na 的部分。 提取数据的正则表达式为:

"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 to phone number +*d+ to user .*

我们需要将 + 符号替换为空格,因为 + 在正则表达式语法中具有特殊含义。 这个含义是“前一个或多个字符”。

符号 d 与任何一位数字匹配。 请记住,* 符号表示“0个或更多前一个字符”。 因此,+*d+匹配一个或多个数字,这些数字可以以 + 符号开头(也可以不加)。

这个正则表达式将把前一个正则表达式匹配的文本替换为相同的文本,但去掉了电话号码和名字:

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"

使用反向引用

假设我们需要将字符串中的 europe 替换为 eu,格式为 west-europe-2。 假设我们不仅需要在 region 字段中,而且需要在日志中任何其他包含该字符串的位置执行此操作。 使用正则表达式可以轻松匹配此模式:

.+?-europe-d+

然而,用我们之前的方法替换字符串可能会相当困难。 这是因为我们需要在 europe 文本的前后插入两串字符,而这两串字符可能会有所不同。 为此,我们首先需要将字符串分组:

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

请记住,d 符号表示“任意数字”,与 + 一起表示“任意数字一次或多次”。 同样,.+ 表示任何符号出现一次或多次,但匹配所需的代币最少。

这个正则表达式将 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]14 中的任意单个字符匹配,而 .* 与任意字符匹配,且匹配次数不限。

有关警报的更多信息,请参阅: