def _write_data_to_file(data: list, file: _io.TextIOWrapper) -> None: """ write data to file :param data: :param file: :return: """ file.writelines(data) file.flush()
def parseLogDir(destDir: str, resonFile: TextIOWrapper, packageName: str = DEFAULT_PACKAGE): #保存所有公共变量 globalValues = GlobalValues() #获取目录下的所有文件 allFiles = toolUtils.getAllFileName(destDir) #获取所有的 system log文件 systemFiles = [file for file in allFiles if 'system.txt' in file] systemFiles.sort(reverse=True) #获取所有的 events log文件 eventFiles = [file for file in allFiles if 'events.txt' in file] eventFiles.sort(reverse=True) #获取所有的 main log文件 mainFiles = [file for file in allFiles if 'main.txt' in file] mainFiles.sort(reverse=True) #获取所有的 radio log文件 radioFiles = [file for file in allFiles if 'radio.txt' in file] radioFiles.sort(reverse=True) #获取所有的 kernel log文件 kernelFiles = [file for file in allFiles if 'kernel.txt' in file] kernelFiles.sort(reverse=True) #获取所有的 crash log文件 crashFiles = [file for file in allFiles if 'crash.txt' in file] #获取所有的 anr trace文件 anrFiles = [ file for file in allFiles if sep.join(['anr', 'anr_' + str(packageName)]) in file ] anrFiles.sort(reverse=False) #获取所有的 system.prop文件 propFiles = [file for file in allFiles if 'system.prop' in file] #解析prop文件获取手机信息 propMsg = toolUtils.parseProp(propFiles) #添加所有需要需要解析的log文件 parseFiles = [] for f in systemFiles: parseFiles.append(f) for f in eventFiles: parseFiles.append(f) for f in mainFiles: parseFiles.append(f) for f in radioFiles: parseFiles.append(f) for f in kernelFiles: parseFiles.append(f) #用于保存重要的信息行LogLine对象 allLine = [] #用于保存所有的Anr对象 allAnr = [] # 从systemui解析有多少个anr systemLog = SystemLog(systemFiles, allAnr, globalValues, packageName) systemLog.findAllAnr() if len(allAnr) == 0: eventLog = EventLog(eventFiles, allAnr, globalValues, packageName) eventLog.findAllAnr() #解析所有的anr trace mainStacks = list() blockStacks = dict() pattern = 'anr_[\w|\.]+_([\d]+)_([\d|-]+)' parseTracesPids = list() tracesLogs = [] for file in anrFiles: match = re.match(pattern, basename(file)) if match: pid = match.group(1) if not pid in parseTracesPids: parseTracesPids.append(pid) willParser = False for anr in allAnr: if str(pid) == str(anr.pid): willParser = True if willParser: log(file) trace = TracesLog(file, globalValues, packageName) trace.parser() tracesLogs.append(trace) stack: ThreadStack = trace.getMainStack() #如果堆栈出现两次相同则加入到数列中 if stack != None: mainStacks.append(stack) #最后一行main log,用于验证main log是否包含anr时间 mainLine = None #保存最后发生anr的时间,当mainLine时间小于anr时间则main log不全 anrTimeFloat = 0 for file in parseFiles: log('--' + file + '--') with open(file, encoding=toolUtils.checkFileCode(file)) as mFile: #全局变量,当前解析的文件 globalValues.currentFile = file linenum = 0 #是否在解析main log isMainLine = True if ('main.txt' in file) else False while True: line = mFile.readline() linenum = linenum + 1 if not line: break else: line = line.strip() temp = LogLine(line, linenum, globalValues) if temp.isLogLine: #保存最后一行main log if isMainLine: if (mainLine == None or temp.timeFloat > mainLine.timeFloat): mainLine = temp if temp.pid == temp.tid: for anr in allAnr: temp.addAnrMainLog(anr) #解析该行 parseLine(allAnr, allLine, temp, packageName) log('####################start write######################') if GLOBAL_VALUES.only_filter: for line in allLine: if line.filter: start = len(dirname(dirname(dirname(destDir)))) + 1 resonFile.writelines("filter: in file {} -> line={}\n".format( line.file[start:], line.linenum)) resonFile.writelines("\t{}\n".format(line.line.strip())) return globalValues #将手机的信息写入到文件 for (key, value) in propMsg.items(): temp = "{}:{}\n".format(key, value) globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) #讲对应的am anr添加到主要信息中 for anr in allAnr: if not anr.anrCoreLine and anr.anrCoreReserveLine: anr.setCoreLine(anr.anrCoreReserveLine) anr.computerAnrTime() anr.findAllCoreLine(allLine) if len(anr.systemAnr.lines) >= 8: for line in anr.systemAnr.lines[0:8]: allLine.append(line) #保存发生anr的pid,从堆栈trace中查找对应的pid pids = [] #将所有的anr信息输出到文件 for anr in allAnr: pids.append(anr.pid) temp = "pid:" + str(anr.pid) + '\n' + "发生时间:" + str( anr.anrTimeStr) + '\n' + "发生原因:" + anr.anrReason + '\n\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) mainMsg: [] = anr.addMainLogBlock(allLine) if mainMsg: font = mainMsg[0] back = mainMsg[1] temp = ('主线程阻塞:{} ==> {}\n\t{}\n\t{}'.format( font.timeStr, back.timeStr, font.line, back.line)) + '\n\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) startDelayLine = anr.anrCoreLine key = lambda line: line.delayStartTimeFloat if anr.anrCoreLines: temp = '核心log:\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) delayLines = [ delayLine for delayLine in anr.anrCoreLines if delayLine.isDelayLine ] for line in delayLines: temp = '\t' + line.line + '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = "\t\tstartTime:{}\n".format(line.delayStartTimeStr) globalValues.showMessage.append(temp) resonFile.writelines(temp) delayLines = sorted(delayLines, key=key, reverse=True) for line in delayLines: if startDelayLine == None or ( line.delayStartTimeFloat < startDelayLine.delayStartTimeFloat and line.timeFloat > startDelayLine.delayStartTimeFloat): startDelayLine = line temp = '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) # 输出阻塞的堆栈 for stack in [ stack for item in mainStacks if str(item.pid) == str(anr.pid) ]: if stack: temp = '\t\nmain pid=' + str(stack.pid) + ' time=' + str( stack.pidStack.time) + ' java栈:' + '\t\n\t' + str( stack.top) + '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = '\t\t' + '\n\t\t'.join(stack.javaStacks if len( stack.javaStacks) < 10 else stack.javaStacks[0:10]) globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = '\n\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) if startDelayLine: temp = '起始阻塞log:\n' + '\t' + startDelayLine.line + "\n\t\tstartTime:{}\n".format( startDelayLine.delayStartTimeStr) + '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) log(anr.anrTimeStr) log(anr.anrTimeFloat) #获取最后发生anr的时间,用于推断main log是否全 if anr.anrTimeFloat > anrTimeFloat: anrTimeFloat = anr.anrTimeFloat log(anr.anrReason) # 将主要信息按时间排序 allLine.sort(key=lambda line: line.timeFloat) #判断是否main log不足 if mainLine != None and (mainLine.timeFloat < anrTimeFloat): log("main log 不足") temp = "main log 不足 time:" + str( toolUtils.getTimeStamp(mainLine.timeFloat)) + '\n\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) #输出pid和线程名称到文件 if len(globalValues.pidMap) > 0: temp = "线程名称:\n\t" resonFile.writelines(temp) globalValues.showMessage.append(temp) count = 0 temp = '' for key in sorted(globalValues.pidMap.keys()): temp = temp + 'pid={} : name={},\t\t'.format( key, globalValues.pidMap[key]) count = count + 1 if len(temp) > 80: temp = temp + '\n\t' globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = '' if len(temp) > 0: resonFile.writelines(temp) globalValues.showMessage.append(temp) #查找最异常binder hungerBinder = dict() maxBinderNum = 0 maxBinder = '' for key, value in globalValues.hungerBinders.items(): newKey = '{}:{}'.format(key.split(':')[0], value.split(':')[0]) if newKey in hungerBinder.keys(): hungerBinder[newKey] = hungerBinder[newKey] + 1 else: hungerBinder[newKey] = 1 if maxBinderNum < hungerBinder[newKey]: maxBinder = newKey maxBinderNum = hungerBinder[newKey] if hungerBinder: temp = '\n\ndump时候异常binder 等待binder共有{}个:'.format( len(globalValues.hungerBinders)) for key, value in hungerBinder.items(): if maxBinderNum == value or value > 3 or len(hungerBinder) == 1: pids = key.split(':') fromPid = int(pids[0]) if fromPid in globalValues.pidMap: fromPid = '{}({})'.format(fromPid, globalValues.pidMap[fromPid]) toPid = int(pids[1]) if toPid in globalValues.pidMap: toPid = '{}({})'.format(toPid, globalValues.pidMap[toPid]) temp = temp + '\n\t其中 binder form pid:{} to pid:{}, 数量 = {}。'.format( fromPid, toPid, value) globalValues.showMessage.append(temp) resonFile.writelines(temp) if len(tracesLogs) > 0 and len(tracesLogs[0].suspiciousStack) > 0: temp = '\n\n阻塞线程\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) for tracesLog in tracesLogs: temp = '\n' for title, stack in tracesLog.suspiciousStack.items(): pidStack: PidStack = stack if len(pidStack.javaStacks) < 10: temp = '{}\t{}\n\t\t{}\n'.format( temp, title, '\n\t\t'.join(pidStack.javaStacks)) else: temp = '{}\t{}\n\t\t{}\n\t\t{}\n\t\t{}\n'.format( temp, title, '\n\t\t'.join(pidStack.javaStacks[:5]), '......', '\n\t\t'.join(pidStack.javaStacks[-4:])) globalValues.showMessage.append(temp) resonFile.writelines(temp) temp = '\n' globalValues.showMessage.append(temp) resonFile.writelines(temp) log("len == " + str(len(allLine))) #未找到相关log if (len(allLine)) == 0 and mainLine != None: log(mainLine.timeFloat) log(anrTimeFloat) else: #输出所有的分析行信息到文件 resonFile.writelines("\n关键log:\n") for line in allLine: if line.filter: start = len(dirname(dirname(dirname(destDir)))) + 1 resonFile.writelines( "\n filter: in file {} -> line={}\n".format( line.file[start:], line.linenum)) resonFile.writelines("\t{}\n".format(line.line.strip())) else: if line.isAnrCore: start = len(dirname(dirname(dirname(destDir)))) + 1 resonFile.writelines( "\n My Anr core: in file {} -> line={}\n\n".format( line.file[start:], line.linenum)) resonFile.writelines("\t{}\n".format(line.line.strip())) if line.isDelayLine: resonFile.writelines("\t\tstartTime:{}\n".format( line.delayStartTimeStr)) resonFile.writelines("\n") # 判断是否有anr if len(allAnr) == 0: temp = ("{}未找到anr报错信息\n".format(basename(destDir))) logUtils.info(temp) globalValues.showMessage.append(temp) resonFile.writelines(temp) log('####################end write######################') return globalValues