在golang中进行高效的日志解析

时间:2019-07-15 23:13:30

标签: go

解析日志文件中的行并提取兴趣点的有效(性能和可读性)是什么?

例如:

*** Time: 2/1/2019 13:51:00
17.965 Pump 10 hose FF price level 1 limit    0.0000 authorise pending (Type 00)
17.965 Pump 10 State change LOCKED_PSTATE to CALLING_PSTATE [31]
38.791 Pump 10 delivery complete, Hose 1, price 72.9500, level 1, value  100.0000, volume    1.3700, v-total 8650924.3700, m-total 21885705.8800, T13:51:38

我需要提取的东西是10(对于泵10),价格水平。限制 _PSTATE更改交货完成行等中的值。

目前,我正在使用正则表达式捕获每个表达式并使用捕获组。但是感觉效率很低,而且有很多重复。

例如,我有一堆:

reStateChange := regexp.MustCompile(`^(?P<offset>.*) Pump (?P<pump>\d{2}) State change (?P<oldstate>\w+_PSTATE) to (?P<newstate>\w+)_PSTATE`)

然后在while循环中

if match := reStateChange.FindStringSubmatch(text); len(match) > 0 {
    matched = true
    for i, name := range match {
        result[reStateChange.SubexpNames()[i]] = name
    }
} else if match := otherReMatch.FindStringSubmatch(text); len(match) > 0 {
    matched = true
    for i, name := range match {
        result[reStateChange.SubexpNames()[i]] = name
    }
} else if strings.Contains(text, "*** Time:") {

}

感觉有更好的方法可以做到这一点。我会为了获得可读性而牺牲一些性能。日志文件实际上最多只有10MB。通常较小。

我正在寻求有关如何在golang中使其变得更好的一些建议。

1 个答案:

答案 0 :(得分:0)

如果您的所有日志行都与您发布的示例相似,则它们似乎结构合理,因此正则表达式可能有点过大且难以一概而论。

另一个选择是,您可以使用strings.Fields甚至是strings.FieldFunc将这些行中的每行转换为一片字符串([]string),以便您可以同时删除两个空格和逗号。

然后您可以设计一个界面,例如:

type LogLineProcessor interface {
    CanParse(line []string)
    GetResultFrom(line []string) LogLineResult
}

LogLineResult是包含所提取信息的结构。

然后,您可以使用实现LogLineProcessor的方法定义多个结构(每个实现都会查看该[]string上的特定位置,以了解它是否可以处理,例如查找希望找到它们的位置上有“软管”,“ FF”和“价格”字样。

GetResultFrom实现也将从[]string中的特定位置提取每个数据点(如果它已经确定它是可以处理的行之一,则可以依赖那里的信息)。

您可以创建一个var processors []LogLineProcessor,将所有处理器放入其中,然后仅迭代该数组:

line := strings.Fields(text)
for _, processor := range processors {
     if processor.CanParse(line) {
        result := processor.GetResultFrom(line)
        // do whatever needed with the result
     }
}