使用正则表达式解析日志是一种从大量日志数据中提取基本信息的宝贵技术。通过采用这种方法,可以有效地识别模式、错误和其他关键见解,最终简化日志分析并提高系统性能。
BindPlane OP 和 BindPlane 代理(自定义 OpenTelemetry 收集器)
需要自定义解析的复杂日志文件
正则表达式知识
匹配所有可能变化的日志样本选择。
(可选)regex101.com等不错的正则测试工具
在这篇文章中,我们将检查类似于下面提供的示例的日志条目。通过使用脚本将这些条目写入具有当前时间戳的文件,我们可以有效地处理实时数据。
May 01 14:31:11 loggen-app10 test-system[712]: Mon May 01 14:31:11 UTC 2023|TEST_PROC|[result=Service Access Granted,service=https://portal.fakeuni.edu/uPortal/Login?...,requiredAttributes={}]|SERVICE_ACCESS_ENFORCEMENT_TRIGGERED|camillec1997|172.13.49.165|172.16.156.55 May 01 14:31:11 loggen-app10 test-system[712]: Mon May 01 14:31:11 UTC 2023|TEST_PROC|[result=Service Access Granted,service=https://portal.fakeuni.edu/uPortal/Login?...,requiredAttributes={}]|SERVICE_ACCESS_ENFORCEMENT_TRIGGERED|camillec1997|172.13.49.165|172.16.156.55 May 01 14:31:11 loggen-app10 test-system[712]: Mon May 01 14:31:11 UTC 2023|TEST_PROC|[event=success,timestamp=May 01 14:31:11 UTC 2023,source=RankedMultifactorAuthenticationProviderWebflowEventResolver]|AUTHENTICATION_EVENT_TRIGGERED|audit:unknown|172.25.178.6|172.16.156.55 May 01 14:31:11 loggen-app08 test-system[780]: Mon May 01 14:31:11 UTC 2023|TEST_PROC|Supplied credentials: [UsernamePasswordCredential(username=dawsonb, source=null, customFields={})]|AUTHENTICATION_SUCCESS|dawsonb|172.12.154.117|172.16.156.53 May 01 14:31:11 loggen-app10 test-system[712]: Mon May 01 14:31:11 UTC 2023|TEST_PROC|[event=success,timestamp=May 01 14:31:11 UTC 2023,source=RankedMultifactorAuthenticationProviderWebflowEventResolver]|AUTHENTICATION_EVENT_TRIGGERED|audit:unknown|172.25.178.6|172.16.156.55
我们现在可以获取上面的第一个日志条目,并开始将其分解为我们希望解析的部分。
首先,我们会注意到我们有两个时间戳:
**May 01 14:31:11** loggen-app10 test-system[712]: **Mon May 01 14:31:11 UTC 2023**|TEST_PROC|[result=Service Access Granted,service=https://portal.fakeuni.edu/uPortal/Login?...,requiredAttributes={}]|SERVICE_ACCESS_ENFORCEMENT_TRIGGERED|camillec1997|172.13.49.165|172.16.156.55
第二个时间戳是我们将保留成为官方时间戳的那个,因为它包含更多信息(时区和年份很有用,而星期几不是真的),我们可以使用这些信息来实现最高精度。
打破这个,我们将编写一个非捕获模式来匹配第一个时间戳。
^\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s+The caret “^”
到行首。接下来是“ \w{3}
”,它捕获了 3 个字母的月份缩写。月份之后是“ \s\d{2}\s
”,就是抓取一个空格; 2 位数字,该月的 0 填充天数;和另一个空间。最后,我们有“ \d{2}:\d{2}:\d{2}\s+
”——代表 2 位数字小时、2 位数字分钟、2 位数字秒和 1 个或多个空格。
对于第二个时间戳,我们需要一个命名的捕获组。这将成为解析字段的 JSON blob 中的命名字段。
(?P<timestamp>\w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\w{3}\s\d{4})
我们将这个捕获组命名为“timestamp”。它包含与其他时间戳相同的基本正则表达式,在开始处添加“ \w{3}\s
”以捕获星期几的缩写,以及“ \s\w{3}\s\d{4}
”替换末尾的“ \s+
”以捕获 3 个字符的时区和 4 位数字的年份。
进一步研究日志消息,我们将要解析主机名和系统:
May 01 14:31:11 **loggen-app10 test-system[712]**: Mon May 01 14:31:11 UTC 2023|TEST_PROC|[result=Service Access Granted,service=https://portal.fakeuni.edu/uPortal/Login?...,requiredAttributes={}]|SERVICE_ACCESS_ENFORCEMENT_TRIGGERED|camillec1997|172.13.49.165|172.16.156.55
在此消息中,我们的主机名是**loggen-app10**
,我们的系统是**test-system[712]**
。当我收到这些日志时,我没有被告知 [712] 是什么。我假设它是PID(进程ID),但我选择暂时不单独解析它。解析这些字段相当简单,我们最终得到:“ (?P<hostname>[^\s]+)\s+(?P<system>.*?):\s+
”。我们有一对命名的捕获组、主机名和系统。
主机名的模式是“ [^\s]+
”,表示捕获任何非空格字符并尽可能多地捕获它们(贪婪)。接下来是“ \s+
”,它至少捕获一个,但尽可能多(再次贪婪)空间。
系统的捕获组甚至更容易,因为在空格之后我们捕获冒号字符之前的所有内容。为此,我们使用“ .*?
”。该模式的意思是,捕获任何字符 0 次或多次,但不要贪心。
在那之后,我们有冒号字符和另外 1 个或多个贪婪的空格。这些没有被捕获,但需要在这部分和我们上面写的时间戳部分之间填充。
这导致以下起始模式:
^\w{3}\s*\d{2}\s*\d{2}:\d{2}:\d{2}\s+(?P<hostname>[^\s]+)\s+(?P<system>.*?):\s+(?P<timestamp>\w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\w{3}\s\d{4})
我不会经历整个模式创建过程,但我会像上面那样继续将其分块。
由此产生的最终模式是:
^\w{3}\s*\d{2}\s*\d{2}:\d{2}:\d{2}\s+(?P<hostname>[^\s]+)\s+(?P<system>.*?):\s+(?P<timestamp>\w{3}\s\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}\s\w{3}\s\d{4})\|(?P<app_name>\w*)\|((?P<message_type>.*?):\s+)?\[?(?P<message>.*)\]?\|(?P<event_message>.*?)\|(?P<username>.*?)\|(?P<external_ip>[\d\.:]*)\|(?P<internal_ip>[\d\.:]*)
这个最终模式包括以下命名的捕获组,它们成为我们解析数据的 JSON blob 中的字段:
在 BindPlane 中,我创建了一个文件源。这会查看我在 /root/complex.log 中生成的日志文件。我在解析格式下选择了正则表达式。在正则表达式模式下,我输入了上面的最终模式。我选中了 Parse Timestamp 框,为格式选择了 Manual,并为我的时间戳模式输入了时间解析代码。
完成后,它看起来像这样:
要完成测试,我需要创建一个目的地并检查那里的数据。对于我的用例,我选择了一个 Google Cloud Logging 目的地。
管道配置完成后,我将其附加到代理。运行片刻后,我单击代理页面上的“查看最近的遥测按钮”
遥测视图向我显示了以下已解析的日志:
最后,我还在Google Cloud Logging 控制台上进行了检查:
这将显示相同的日志条目,并且它具有来自最近遥测视图的我们身体的 JSON 映射对象的 JSON 有效负载。
对于接下来的步骤,我想看看解析该消息值。它通常是一个键/值集;正如上面的屏幕截图和示例所示。我可以将数据向前传递给处理器,处理器将这些键/值条目解析为另一层 JSON。在上面的示例中, body.message
将被解析回自身,您可以拥有如下字段:
body.message.result=Service Access Granted body.message.service=https://innosoftfusiongo.com/sso/logi… body.message.principal=SimplePrincipal(id=dawsonb, attributes={mail=[[email protected]], eduPersonAffiliation=[Staff], ou=[Recreation/Student Rec Center], givenName=[Dawson], cn=[Dawson Branden], title=[Asst. Director], employeeNumber=[5000000], o=[Vice ChancellorStudent Affairs], fakeuniOrg=[Vice ChancellorStudent Affairs], casMFARequired=[YES], uid=[dawsonb], eduPersonPrimaryAffiliation=[Staff], fakeuniCid=[5000000], fakeuniSeparationDate=[99991231000000Z], UDC_IDENTIFIER=[dawsonb], sn=[Branden], organizationalStatus=[Staff]}) body.message.requiredAttributes=””
即使这样也可以通过将 body.message.principle 放入键/值解析器来进一步解析。
现在,肯定有人会疑惑,“为什么不直接使用正则表达式解析 body.message 子字段呢?”答案是:太不一致了。当我们已经具备解析键/值对的能力时,正则表达式将变得难以置信且不合理地复杂。
在日志文件中可以找到多种形式的数据。这些数据通常需要进行解析,以使其更易于人类阅读,并更易于链中后期的自动化和工具采取行动。
虽然我使用的示例是在一个简单的文件日志上执行的,但此处的技术可用于任何日志流。除了正则表达式解析,BindPlane 还支持JSON 、XML 、键/值对和字符分隔值。通过使用处理器,这些解析器可以链接在一起以解析嵌入式数据,并将其全部处理成可用格式。
也发布在这里。