背景
工作中有需要从一个日志文件中提取打印的通信数据报文。日志打印有几十万行,而里面的报文也很长,分了几百个块发送,因此相关日志也有几百行,但是相关日志的格式是有特点的。因此我决定写个python脚本,把通信数据报文输出用于进一步分析。
报文日志打印的格式特点是含有“multiFrame is:”和“07470136”这两个字符,第二个字符串后面有两个字符的编号,编号后就是报文内容。
[SendMultiFrame] Debug! multiFrame is:01122********************0747013601555555555555
......
[SendMultiFrame] Debug! multiFrame is:01122********************0747013602555555555555
......
[SendMultiFrame] Debug! multiFrame is:01122********************0747013603555555555555
......
代码实现
import zlib
def extract_from_log():
f = open("log.txt", "r") # 日志文件
f_data = open("result.txt", "w") # 日志文件里的通信数据
# f_out = open("resultdata.txt", "w") # 日志文件里通信数据每字节一行写入,是否要用看实际需要
file_data = f.readlines()
data = []
print('data is:')
for content in file_data:
# 本用例里通信数据所在行的特征是 含有“multiFrame is”和“7470136”关键词,并且第90位开始到最后“\n”前是数据
if 'multiFrame is' in content:
if '7470136' in content:
content = content.replace("\n", "")
print(content[89:])
f_data.writelines(content[89:])
data.append(content[89:])
packagedata = "".join(data)
# 由于数据是16进制打印,所以每两个字符的长度是一个字节
datalength = len(packagedata) // 2
dataList = []
for i in range(0, datalength):
dataList.append(packagedata[2 * i] + packagedata[2 * i + 1]) # 每个字节由相邻两个16机制字符组成
for i in range(0, datalength):
# f_out.write(dataList[i] + "\n") # 日志文件里通信数据每字节一行写入,是否要用看实际需要
dataList[i] = int(dataList[i], 16) # 计算CRC32需要int格式
# 最后计算从日志文件中提取的通信报文数据长度和CRC32值,用于确认是否提取正确
data_out_CRC32 = zlib.crc32(bytes(dataList))
print('datalength is:', datalength)
print("crc32 of printed data is:%#x" % data_out_CRC32)
#通过日志上文得知这里的数据是intel hex格式的,根据对该格式的了解,复原了原始的hex文件
f_hex = open("result_hex.txt", "w") # 日志文件里的通信数据
for i in range(datalength):
if i % 0x10 == 0 and i < 97265:
firstpart = 0x108000 + i
if firstpart >= 0x110000:
firstpart = firstpart - 0x10000
if firstpart == 0x100000:
# print(':020000021000EC')
f_hex.write(':020000021000EC' + "\n")
firstpartprint = str(hex(firstpart))[2:].upper()
datalineprint = ':'
datalineprint = "".join((datalineprint, firstpartprint))
datalineprint = "".join((datalineprint, '00'))
Sum = 0
for j in range(16):
if (i + j) >= datalength:
break
Sum = Sum + dataList[i + j]
dataprint = str(hex(dataList[i + j]))[2:].upper()
if len(dataprint) == 1:
dataprint = "".join(('0', dataprint))
datalineprint = "".join((datalineprint, dataprint))
a1 = (firstpart & 0xff0000) >> 8 * 2
a2 = (firstpart & 0x00ff00) >> 8
a3 = firstpart & 0x0000ff
a_firstpart = a1 + a2 + a3
#crc计算的算法是将所有的数相加,然后计算补码
Checksum = 0x100 - (Sum + a_firstpart) & 0xff
checksumprint = str(hex(Checksum))[2:].upper()
if len(checksumprint) == 1:
checksumprint = "".join(('0', checksumprint))
datalineprint = "".join((datalineprint, checksumprint))
# print(datalineprint)
f_hex.write(datalineprint + "\n")
# print(':00000001FF')
f_hex.write(':00000001FF' + "\n")
if __name__ == '__main__':
extract_from_log()
测试结果
测试日志打印:
data is:
55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
......
datalength is: 94444
crc32 of printed data is:0x3108c3d5
Process finished with exit code 0
生成一个新的文件(intel hex文件):
:108000004B4F5354414CFFFF0001FBE0FFFFFFFFCC
:10801000ED108100ED118400ED148400ED17840053
......
:10FBE0004B4F434849FFFFFF0001FBF8FFFFFFFFBA
:00000001FF
测试结果分析
经过和日志里数据长度打印和CRC32校验值比对,上述代码提取的报文数据是正确的。