需求
1.解析服务端日志文件,计算每一笔的通讯的用时
2.日志文件样例
[00:00:00.002][T]PUB-INIT[32336] begin G1_PUB_INIT_467.log
[00:00:00.009][T]PUB-INIT[32336] end
3.日志说明:第三个[]中的数据在单个文件中唯一,用此作为一笔通讯的关键字
4.文件说明
4.1 日志文件名为:G1_PUB.log
4.2 输出文件名为:G1_PUB_TAG.log
实现
# -*- coding: utf-8 -*-
import re
from datetime import datetime
filepath=r"./G1_PUB.log"
filepath_tag=r"./G1_PUB_TAR.csv"
filetag=open(filepath_tag,'a')
patternsplit = r'\[([^\]]+)\]'
restdict={}
# 读取日志文件的每一行
with open(filepath, 'r') as file:
for line in file:
line = line.strip() # 去除行首尾空白
splitline=re.split(patternsplit,line)
del splitline[3]
if 'begin' in line:
splitline[5]=splitline[5].split(' ')[2]
restdict[splitline[4]]=splitline
elif 'end' in line:
end_time=splitline[1]
start_time=restdict[splitline[4]][1]
end_time_fmt = datetime.strptime(end_time, '%H:%M:%S.%f')
start_time_fmt = datetime.strptime(start_time, '%H:%M:%S.%f')
restdict[splitline[4]][2]=splitline[1]
duration = end_time_fmt - start_time_fmt
fmtdur=str(int(duration.total_seconds() * 1000))
restdict[splitline[4]][0]=fmtdur
filetag.write(", ".join(restdict[splitline[4]]))
filetag.write('\n')
del restdict[splitline[4]]
filetag.close()
将以上代码保存到服务器文件如G1_PUB_Parse.py
执行如下命令,即可得到结果csv文件
pyhton G1_PUB_Parse.py
将csv文件使用数据分析方法或者excel排序则可以获得进一步的处理。
结果文件一行如下图
24, 20:30:26.129, 20:30:26.153, PUB-INIT, 49290, G1_PUB_INIT_210.log
结果集文件说明
单笔用时(单位毫秒),起始时间,结束时间,服务,单笔ID,单笔日志文件名称
代码说明
pyhton注意事项
文件开头编码说明
# -*- coding: utf-8 -*-
python脚本文件缺少此说明,会报错如下错误:
SyntaxError: Non-ASCII character '\xe8' in file G1PUBParse.py on line 4, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
错误说明:
1.服务器使用的是python2的版本
2.错误表明脚本文件中存在非ASCII字符。Python 2中默认不支持Unicode,因此当文件中包含像\xe8这样的非ASCII字符(通常是UTF-8编码的字符)时,Python解释器会抛出此错误。
3.可以使用别的方法处理,如使用python3等
处理思路
- 读取每一行,处理每一行
- 用正则表达式分割每一行(正则的规则是方括号,根据文件记录类型而动)
- 拆解后的结果集为list
- 将list第一位存差值,第三位存单笔的结束时间,每行的唯一id存入字典的key,每行数据作为该可以对应的value
- 将已计算的时间写入目标文件
- 已写入目标文件的键值对从字典中删除
- 关闭文件流
读取每一行,处理每一行
with open(filepath, 'r') as file:
for line in file:
每行数据去除行首尾空白
line = line.strip()
使用[]分割字符串正则
# 预定义的正则表达式
patternsplit = r'\[([^\]]+)\]'
# 正则表达式分割数据
splitline=re.split(patternsplit,line)
删除分割后数据中无用的T
del splitline[3]
处理带有begin的数据
# 从分割后的结果集拆出日志文件名,即“ begin G1_PUB_INIT_998.log” 取成“G1_PUB_INIT_998.log”
splitline[5]=splitline[5].split(' ')[2]
# 将处理后的行存入map中
restdict[splitline[4]]=splitline
处理带有end的数据
# 获取结束时间
end_time=splitline[1]
# 获取开始时间
start_time=restdict[splitline[4]][1]
# 格式化时间
end_time_fmt = datetime.strptime(end_time, '%H:%M:%S.%f')
start_time_fmt = datetime.strptime(start_time, '%H:%M:%S.%f')
# 将结束时间存入dict
restdict[splitline[4]][2]=splitline[1]
# 计算每笔用时
duration = end_time_fmt - start_time_fmt
# 用时格式化成毫秒级字符串
fmtdur=str(int(duration.total_seconds() * 1000))
# 将格式化后的时间存入dict的value
restdict[splitline[4]][0]=fmtdur
# 将处理后的list用“, ”分割写入文件
filetag.write(", ".join(restdict[splitline[4]]))
# 每行写入换行符
filetag.write('\n')
# 删除已用过的数据
del restdict[splitline[4]]
关闭文件流
filetag.close()
总结
- 写程序时最好遵守该语言的规范,避免一些错误
- 弄清楚使用的各个版本