ecFlow笔记:ecFlow日志解析 - 通用字段
本文属于介绍 NWPC 工作流日志工具的系列文章。
上一篇文章《ecFlow笔记:ecFlow日志分类》介绍 ecFlow 日志的几种常见类型。 本文介绍如何解析日志条目的通用字段。
本文代码均来自 nwpc-oper/nwpc-workflow-log-model 项目。
通用结构
ecFlow 日志条目有相似的结构。
下面是 4 种主要类型的日志条目示例,并用不同的颜色区分不同的字段。
可以看到,所有条目的开头都有相同格式,包含日志级别(Log type / Log level)和时间(Datetime)两个字段。 而不同类型的日志由 Command(Event Type)字段区分。 大部分日志包含节点路径(Node path)。 少部分日志包含与命令相关的附加信息(Additional Information)。
ecFlow 日志条目的通用对象包含如下字段:
- 日志级别(Log Type)
- 日期(Date)
- 时间(Time)
- 日志事件(Event)
- 节点路径(Node Path)
- 附加信息(Additional Information)
不同类型的日志对象可有自己特定的字段。 如下图所示
通用解析
ecFlow 的所有日志,都以日志层次和时间开头。所以解析日志时首先寻找 :
符号,获取日志层次;再寻找 ]
符号,获取日志的日期和时间。
然后根据 ]
后续的少量字符来判断日志的类型。
]
后面如果有一个空格,表明条目是状态变化记录。例如
LOG:[17:24:11 8.6.2020] complete: /grapes_tym/grapes_d01/12/prods/plot/plot_036
]
后面是 chd:
,表明条目是 child 命令记录。例如
MSG:[17:24:11 8.6.2020] chd:complete /grapes_tym/grapes_d01/12/prods/plot/plot_036
]
后面是 --
,表明条目是 client 命令记录。例如
MSG:[17:24:11 8.6.2020] --sync=0 3804359 182 :nwp_pd
]
后面是 svr:
,表明条目是服务端记录。例如
MSG:[17:25:17 8.6.2020] svr:check_pt in 0 seconds
根据日志类型,再执行与其相关的解析。
整个解析过程如下图所示:
目前 NWPC 工作流日志工具只支持上述 4 种类型的日志解析,其余日志会被忽略。
实现
请参考 nwpc-workflow-log-model 项目的 EcflowLogParser
类的 parse 函数
以下代码来自该函数,其中 self
表示 EcflowLogParser
类,line
是日志条目字符串。
日志层次
搜索 :
,获取日志层次字符串,并使用 _parse_log_type
函数转换。
log_record = EcflowLogRecord(log_record=line)
start_pos = 0
end_pos = line.find(":")
log_type_token = line[start_pos:end_pos]
log_type = self._parse_log_type(log_type_token)
log_record.log_type = log_type
时间戳
继续搜索 ]
,获取日期时间字符串。
start_pos = end_pos + 2
end_pos = line.find("]", start_pos)
if end_pos == -1:
logger.warning(f"can't find date and time => {line}")
return None
date_time_token = line[start_pos:end_pos]
注意:这里没有立即解析时间戳,因为解析时间比较耗时,如果日志条目被忽略,解析时间会造成资源浪费。
判断日志类型
根据后续 1 - 4 位字符判断日志类型。下面代码省略具体的解析步骤。
start_pos = end_pos + 2
if line[start_pos: start_pos + 1] == " ":
# status event
pass
elif line[start_pos: start_pos + 2] == "--":
# client event
pass
elif line[start_pos: start_pos + 4] == "chd:":
# child event
pass
elif line[start_pos: start_pos + 4] == "svr:":
# server event
# MSG:[05:41:25 2.2.2020] svr:check_pt in 0 seconds
pass
else:
# other
pass
调用类型相关解析
使用具体的日志条目对象,解析提取过日志层次和时间戳后剩余的字符串。
date_time = self._parse_datetime(date_time_token)
log_record = StatusLogRecord(
log_type=log_type,
date=date_time.date(),
time=date_time.time(),
log_record=line,
)
start_pos += 1
log_record.parse_record(
line[start_pos:],
debug=self.options[EventType.Status]["debug"],
)
return log_record
后续文章会详细介绍各个类型的解析,这里仅作简要说明。