事件模式匹配:ChronEx 简介

在处理日志文件时,寻找特定事件的实例可能并不困难,但当模式中包含变量元素时,寻找特定事件模式就会变得极其困难。ChronEx 是一种模式匹配规范和参考实现,允许开发者或商业智能分析师以类似于文本中的正则表达式(RegEx)匹配的方式,指定要匹配的事件模式。

以正则表达式为例,假设有一个日志文件,其中可能包含名为 "A"、"B"、"C"、"D" 或 "E" 的事件。需要在日志文件中搜索所有事件 "A" 发生两次,紧接着是事件 "B",然后是事件 "C" 或 "D",最后是事件 "E" 的实例。幸运的是,日志将所有事件保存为单行字符串中的字符序列。查询日志的最简单方法是使用正则表达式 "A{2}B(C|D)E"。这个正则表达式将找到日志中所有这种特定模式的实例。

将这个概念扩展到 ChronEx,假设这些事件有更详细的名称,并存储在日志中。可以使用如下 ChronEx 模式:

EventA{2} EventB [ EventC EventD ] EventE

这个模式在运行时,将类似于在字符串上运行正则表达式时的行为。

使用代码

ChronEx 是一种模式匹配语言的规范。目前有一个部分C#参考实现,并且正在开发Python实现。规范在 GitHub 上的地址是:

https://github.com/mbadler/ChronologicalExpressions

C#实现在:

https://github.com/mbadler/ChronEx-CSharp

这些都是非常早期且非常粗糙的实现。欢迎任何人提交建议、改进等。

所有 ChronEx 的事件输入都是 IChronologicalEvents 的列表:

public interface IChronologicalEvent { string EventName { get; } DateTime? EventDateTime { get; } }

该库有帮助方法可以解析 CSV 并生成适合在 ChronEx 中使用的一系列对象。

ChronEx 类包含运行模式匹配的方法:

public static bool IsMatch(string ChronExStatment, IEnumerable Events)

如果有任何事件模式匹配,则此方法返回布尔值 true/false:

public static int MatchCount(string ChronExStatment, IEnumerable Events)

此方法返回事件日志中的模式数量(不是实际事件的数量,而是模式匹配的数量):

public static ChronExMatches Matches(string ChronExStatment, IEnumerable Events)

此方法返回一个包含每个模式的匹配事件的匹配列表。这些全部是静态方法,接受模式,Lex,解析并构建运行表达式所需的 AST(抽象语法树)。最终,将添加方法来实例化这些模式,使用预先解析的 AST 以加快构建速度。

ChronEx 与 RegEx 的比较

之前提到 ChronEx 基于 RegEx,确实是这样,但非常松散。现在的大多数正则表达式引擎是 RDE(Regex Driven Engines),而不是所谓的 TDE(Text Driven Engine)。这指的是什么驱动引擎,是枚举文本还是模式。TDE 简单且比 RDE 快得多,但 RDE 提供了更多的功能,非贪婪选择器和前瞻是 TDE 不可用的。

从这个意义上说,ChronEx 可以被认为是 EDE(Event Driven Engine?)。它枚举事件流并应用模式。这是出于两个原因:作为 EDE 更容易编写。事件适合作为流进行处理,在正则表达式中 - 预期已经拥有想要处理的完整文本在内存中,然后可以让正则表达式根据需要在文本中移动。对于事件日志,需要能够处理可能包含数百万事件的日志,因此需要使用流,仅在引擎需要时加载数据,并允许已处理的旧数据根据需要从内存中清除。实际上 - 尽管尚未实现 - 可以看到有长期运行的实时模式,它们将不断运行,并在日志中添加新事件时通知,并实时输出匹配项。

当前实现的功能

截至版本 0.8,这是当前实现的功能。

功能 描述

选择器 事件名称的逐字匹配

正则表达式选择器 以斜杠开头并以斜杠结尾的文本 - 正则表达式表达式将用于匹配事件名称

.(点) 匹配任何事件

* 当附加到选择器或组时 - 匹配 0 个或多个匹配该选择器的事件

? 当附加到选择器或组时 - 匹配 0 个或 1 个匹配该选择器的事件

+ 当附加到选择器或组时 - 匹配 1 个或多个匹配该选择器的事件

!(否定) 当附加到选择器时 - 如果选择器不匹配,则匹配

- 指示匹配但不返回/捕获特定事件

( )(AND 组) 如果组中的所有项匹配,则匹配 允许嵌套组

[ ](OR 组) 如果组中的任何选择器匹配,则匹配(注意,对于版本 0.8 - 仅支持在或组中使用基本选择器,嵌套组将编译,但结果可能是错误的)

{X,X}(数值量词) 将匹配特定数量的事件(正则表达式风格)

尝试 ChronExQuery

包含在存储库中并附加到本文的是一个简单的模式查询应用程序。它附带了一个从建筑能源监控系统适应的数据集,日志包含在建筑锅炉中发生的事件列表,时间跨度为 24 小时。

日志看起来像这样:

BoilOn,Feb 18 2018 1:21PM BoilOff,Feb 18 2018 1:25PM BoilOn,Feb 18 2018 1:25PM BoilOff,Feb 18 2018 1:26PM BoilOn,Feb 18 2018 1:27PM BoilOff,Feb 18 2018 1:30PM

建筑所有者报告说锅炉在燃料成本上花费很多,从日志的前 6 行快速查看,确实看到在下午的 9 分钟期间,锅炉运行了大约 8 分钟,这看起来是过度的。

ChronExQuery 有三个标签,第一个标签是日志。第二个包含查询和结果。如果想分析其他日志 - 只需替换第一个标签中的日志。第三个标签将显示执行的最后一个表达式的序列化 AST。

快速查看日志告诉有很多与 BoilOn 事件匹配的 BoilOff 事件。让找出这个事件覆盖了多少个周期。

模式:

BoilOn

结果:

MatchCount: 389

好的,现在让看看一个典型的 BoilOn/BoilOff 周期是什么样子:

模式:

BoilOn BoilOff

结果:(最后 4 个)

结果 #347

BoilOn : 2/19/2018 12:50:00 PM BoilOff : 2/19/2018 12:53:00 PM

结果 #348

BoilOn : 2/19/2018 12:53:00 PM BoilOff : 2/19/2018 12:56:00 PM

结果 #349

BoilOn : 2/19/2018 12:56:00 PM BoilOff : 2/19/2018 12:58:00 PM

结果 #350

BoilOn : 2/19/2018 1:00:00 PM BoilOff : 2/19/2018 1:00:00 PM

但等等,之前说有 389 个结果,但现在只列出了 350 个,原因是在锅炉运行时可能会发生其他事件,所以需要一个表达式来考虑这一点。

以下模式将从 BoilOn 开始,但然后会寻找 BoilOff,允许多个非 BoilOffs。

BoilOn !BoilOff* BoilOff

结果显示这些类型的模式,例如:

结果 #280

BoilOn : 2/19/2018 7:19:00 AM HTMOn : 2/19/2018 7:20:00 AM HMComp : 2/19/2018 7:20:00 AM BoilOff : 2/19/2018 7:22:00 AM

但查看最后一个结果,看到了一些问题:

结果 #372

BoilOn : 2/19/2018 12:59:00 PM HWOn : 2/19/2018 1:00:00 PM BoilOn : 2/19/2018 1:00:00 PM BoilOff : 2/19/2018 1:00:00 PM

这里有两个问题:

只得到了 372 个结果。预期的是 389。

有一个 BoilOn 没有与 BoilOff 匹配。

所以看起来也有数据质量问题,需要量化并看看这个问题有多严重。

所以让定义一个破损的周期是一个 BoilOn 后面跟着另一个 BoilOn,然后是 BoilOff。这个模式使用正则表达式定义了一个否定的 OR:

BoilOn !/BoilOff|BoilOn/* BoilOn !BoilOff* BoilOff

结果确实显示大约有 15 个破损的周期。例如,这是最后 2 个破损的周期:

结果 #14

BoilOn : 2/19/2018 11:57:00 AM BoilOn : 2/19/2018 12:00:00 PM BoilOff : 2/19/2018 12:01:00 PM

结果 #15

BoilOn : 2/19/2018 12:59:00 PM HWOn : 2/19/2018 1:00:00 PM BoilOn : 2/19/2018 1:00:00 PM BoilOff : 2/19/2018 1:00:00 PM

所以将定义一个锅炉运行事件从 BoilOn 开始,并在下一个 BoilOff 或如果在此之前遇到 BoilOn 时结束。这是将要使用的模式:

BoilOn ![ BoilOn BoilOff ]* BoilOff?

正如预期的那样,得到了预期的所有结果:

结果 #387

BoilOn : 2/19/2018 12:59:00 PM HWOn : 2/19/2018 1:00:00 PM BoilOn : 2/19/2018 1:00:00 PM BoilOff : 2/19/2018 1:00:00 PM
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485