基于PyParsing的Syslog解析求助:适配FortiSIEM格式
Syslog解析器修复:解决PyParsing解析报错与输出为空问题
问题背景
需开发Syslog解析器,将含类JSON键值对的Syslog转换为FortiSIEM兼容的TXT文件,但现有PyParsing脚本出现两类报错:
- 解析日志行提示
Expected ' ', found '2022' - 解析空行提示
Expected '<'
且输出文件为空。示例日志格式:
<140>1 2022-05-02T08:31:22.478Z platform dataexport - syslog_variation - {"key"=value, info:{"key"=value, "key"=value, "key"=value}, info2:{"key"=value, "key"=value},"key"=value}
期望输出格式:
<140>1 2022-05-02T08:31:22.478Z platform dataexport - syslog_variation -
key=value
info.key=value
info2.key=value
...
错误原因分析
- 头部解析逻辑错误:原脚本用
CharsNotIn("\n")定义msgid,未正确处理头部字段间的空格分隔;version等字段的Suppress(" ")写法无法适配多空格场景,导致头部解析失败。 - 空行未过滤:脚本未跳过空行,空行无
<开头触发解析报错。 - 不支持嵌套结构:原脚本无法解析
info:{...}这类嵌套对象,且未处理类JSON中混用的:和=分隔符。 - 输出逻辑错误:直接写入PyParsing的
ParseResults对象会触发类型错误,且未按要求拆分头部与扁平化键值对。
修复后的脚本
from pyparsing import ( Word, Suppress, alphanums, CharsNotIn, ZeroOrMore, Dict, White, Regex, Forward, Group, delimitedList ) # 定义Syslog头部字段 priority = Suppress("<") + Word(alphanums) + Suppress(">") version = Word(alphanums) timestamp = Regex(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z") hostname = Word(alphanums + "-.") appname = Word(alphanums + "-") procid = Word(alphanums + "-") | Suppress("-") msgid = Word(alphanums + "-") | Suppress("-") # 组合头部,处理字段间任意空格 header = ( priority + Suppress(White()) + version + Suppress(White()) + timestamp + Suppress(White()) + hostname + Suppress(White()) + appname + Suppress(White()) + procid + Suppress(White()) + msgid ) # 定义嵌套键值对解析规则 key = Word(alphanums + "_") value = Forward() simple_value = CharsNotIn("{,}\n ") nested_obj = Suppress("{") + delimitedList(Group(key + (Suppress("=") | Suppress(":")) + value)) + Suppress("}") value << (simple_value | nested_obj) # 顶层键值对解析 pair = Group(key + (Suppress("=") | Suppress(":")) + value) kv_pairs = Suppress("{") + delimitedList(pair) + Suppress("}") # 完整消息格式 message = header + Suppress(White()) + kv_pairs # 扁平化嵌套键值对 def flatten_kv(pairs, parent_key=""): flat = [] for key_val in pairs: current_key = f"{parent_key}.{key_val[0]}" if parent_key else key_val[0] if isinstance(key_val[1], list): flat.extend(flatten_kv(key_val[1], current_key)) else: flat.append(f"{current_key}={key_val[1]}") return flat # 处理输入输出文件 with open("syslog.txt", "r") as input_file, open("syslog_output.txt", "w") as output_file: for line_num, line in enumerate(input_file, 1): line = line.strip() if not line: continue # 跳过空行 try: parsed = message.parseString(line, parseAll=True) # 拼接头部字符串 header_str = " ".join(parsed[:7]) # 提取并扁平化键值对 kv_list = parsed[7:] flat_kv = flatten_kv(kv_list) # 按要求格式写入 output_file.write(f"{header_str}\n") output_file.write("\n".join(flat_kv) + "\n\n") except Exception as e: print(f"Line {line_num} parse failed: {line} | Error: {e}") continue
关键修复说明
- 头部解析优化:用
Suppress(White())处理任意空格,正则精准匹配RFC3339格式时间戳,支持-作为procid/msgid的占位符。 - 空行过滤:添加判断跳过空行,避免无效解析报错。
- 嵌套结构支持:通过
Forward()实现递归解析嵌套对象,兼容:和=两种键值分隔符。 - 扁平化处理:新增函数将嵌套键值对转为
parent.key=value格式,适配FortiSIEM的解析需求。 - 输出逻辑修正:正确拼接头部与扁平化键值对,确保输出格式符合要求。
内容的提问来源于stack exchange,提问作者Filipe Gonçalves
相关产品推荐
相关产品推荐

