python——筛选crash_log
【内容】筛选出crash_log中的包名,错误类型,详情。正则包含不了的情况,脚本会单独放到一个txt文件里,命名为“正则未匹配.txt”
【log匹配规则】在保持的字符串中, 先以空格分割,寻找到以"Exception:“结尾,但不是"java.lang.RuntimeException:”,获取到字符串,则去掉结尾":".
Count_crash_log.py的内容:
注释都写在里面了
import os
import re
import csv
import pandas
import easygui
def write_txt(file, s):
with open(file, 'a', encoding='utf-8') as f:
return f.write(s + '\n\n\n\n\n')
def read_txt(file):
try:
with open(file, 'r', encoding='utf-8') as f:
return f.read()
except:
return ''
def write_csv_with_name(filepath, lines: list, columns: list):
if os.path.exists(filepath):
with open(filepath, 'a', newline='', encoding='utf-8-sig') as f:
csv_file = csv.writer(f, delimiter=',')
csv_file.writerows(lines)
else:
with open(filepath, 'a', newline='', encoding='utf-8-sig') as f:
csv_file = csv.writer(f, delimiter=',')
csv_file.writerow(columns)
csv_file.writerows(lines)
# 报错详情,解析文本文件
def parse(file):
txt = read_txt(file)
# 将其分割成多个部分,每个部分以字符串"FATAL EXCEPTION"作为分隔符
parts = re.split('(?=FATAL EXCEPTION)', txt)
# 定义字典对象records
records = {}
for part in parts:
if 'FATAL EXCEPTION' not in part:
continue
# 剔除“crash_dump helper failed to exec, or was killed”
part = re.sub('.*crash_dump helper failed to exec, or was killed.*\n', '', part)
# 分割出包名
# 从字符串 part 中提取出以 AndroidRuntime: Process: 开头,以 , 结尾的部分,然后将其赋值给变量 name。
name = re.findall('AndroidRuntime: Process: (.*?),', part)
if name:
name = name[0]
else:
continue
# 报错类型匹配规则,总体
error = re.findall('''RuntimeException:.*?: (.*?Exception)''', part)
# 如果不符合总体的匹配规则,特殊
if not error:
error = re.findall(r'RuntimeException:.*?: (.*?\$k):', part)
if not error:
error = re.findall(r'RuntimeException:.*?: (.*?\$k):', part)
if not error:
error = re.findall(r'''AndroidRuntime: (.*?Exception)''', part)
if not error:
error = re.findall(r'''AndroidRuntime: (.*?OutOfMemoryError)''', part)
if error:
error = error[0]
else:
print(part + '\n\n\n\n')
write_txt('正则未匹配.txt', part)
continue
# 使用正则表达式来匹配字符串中的特定格式,并将其替换为空字符串。
# 然后,将处理后的字符串按行分割,并去掉前三行,最后将剩余的行重新组合成一个字符串。
detail = re.sub('(.*?: [\t]{0,1})', '', part).split('\n')[3:]
detail = '\n'.join(detail)
# 如果结果为空,则跳过该部分
if detail == []:
continue
# 使用了一个字典变量 records。如果记录中已经存在该错误类型,则将其出现次数加 1;否则,将该错误类型添加到记录中,并将其出现次数设置为 1。
if (name, error, detail) in records.keys():
records[name, error, detail] += 1
else:
records[name, error, detail] = 1
# 最终返回一个字典对象records,其中包含每个不包含"FATAL EXCEPTION"的部分
return records
while True:
# 显示一个简单的消息框,让用户选择目录,并将用户选择的目录路径保存到变量 path 中
path = easygui.diropenbox('选择日志所在的主目录', '选择日志所在的主目录')
# 判断用户选择的路径是否为目录
if os.path.isdir(path):
break
else:
easygui.msgbox('必须选择目录,不能是文件', '必须选择目录,不能是文件')
continue
all = {}
# 使用一个循环遍历前面多个日志文件的解析结果,并将它们合并到一个字典 all 中
# os.walk遍历所有子目录和文件
for paths, dirnames, filenames in os.walk(path):
for name in filenames:
log_path = os.path.join(paths, name)
# 不包含 'crash_log',则跳过
if 'crash_log' not in name:
print(log_path, '不是日志,跳过')
continue
# 把(name, error, detail)当做字典的键,直接判断是不是存在,存在就累加,不存在就创建
print(log_path, '开始处理')
result = parse(log_path)
for key in result.keys():
if key in all.keys():
all[key] += result[key]
else:
all[key] = result[key]
# 将字典转换成一个列表,其中每个元素都是一个列表
# all.keys()获取字典中所有的键
# *key将键拆分成若干个参数
all = [[*key, all[key]] for key in all.keys()]
data = pandas.DataFrame(all, columns=['问题应用', '报错类型', '报错详情', '报错类型数量'])
data.sort_values(by=['问题应用', '报错类型', '报错次数'], inplace=True, ascending=False)
# 报错类型加上序号
numbers = []
pre = None
count = 1
for leixing in data['报错类型']:
""" 对 data['报错类型'] 中的每个元素进行计数,并将计数结果存储在 numbers 列表中
使用变量 pre 记录上一个处理的元素,初始值为 None。
然后遍历 data['报错类型'],如果当前元素和上一个元素不同,则将上一个元素的计数结果添加到 numbers 列表中,并将计数器 count 重置为 1。
如果当前元素和上一个元素相同,则将计数器 count 加一。最后将最后一个元素的计数结果添加到 numbers 列表中。
"""
# 统计中报错类型中连续出现相同词的数量,将结果存储在列表 numbers 中
if pre == None:
pre = leixing
numbers.append(count)
count += 1
continue
if leixing == pre:
numbers.append(count)
count += 1
continue
if leixing != pre:
count = 1
numbers.append(count)
count += 1
pre = leixing
continue
data.insert(2, column='报错序号', value=numbers)
counts = data.groupby('问题应用').sum('报错类型数量')
new_colunm = []
for index, row in data.iterrows():
new_colunm.append(counts['报错类型数量'][row['问题应用']])
data.insert(1, column='报错次数', value=new_colunm)
data.insert(6, column='审核分析', value=None)
data.insert(7, column='解决方案', value=None)
data.to_excel('crash_log_result.xlsx', index=None, columns=['问题应用', '报错序号', '报错类型', '报错次数', '报错详情', '审核分析', '解决方案'])
正则是找规律,提供的日志里面有现有正则包含不了的情况我就增加正则,没出现过的我也猜不到,也没法处理
没法处理的我就单独放到一个txt文件里,命名为“正则未匹配.txt”
后续需要加新的规则的话,请自行在py脚本中增加
运行时间会根据文件大小增加
(以防脚本在新电脑里没配有环境,可以把脚本打包成应用)
【用法】运行Count_crash_log.exe