#!/usr/bin/env python # # crashlytics.py -- summarise multiple `DiagnosticReports` `.crash` files # # Usage: # # ./crashlytics.py ~/Library/Logs/DiagnosticReports/lmms_* # # Author: # Version: 0.1 # License: GPL3+ # # See also: # * # * # * "Q: Can I decode the crash data?" # * # * # import sys class Backtrace(object): """ """ def __init__(self, lines): """ """ self.lines = lines class CrashReport(object): """ """ def __init__(self, file_path): """ """ self.info = {} self.backtraces = [] self.file_path = file_path self._file = open(file_path, "r") self._parse_header() self._skip_to_backtraces() # TODO: Don't be so hacky? if self.info["Crashed Thread"].startswith("0"): self.backtraces.append(self._parse_backtrace()) # TODO: Parse other backtraces? # TODO: Parse end of file? def _parse_header(self): """ Parses "Header" and "Exception Information" sections. """ for line in self._file: #print line, line = line.rstrip() if line: key, value = line.split(":", 1) self.info[key] = value.lstrip() if key == "Report Version": # TODO: Panic on unknown report version? pass if key == "Exception Codes": break def _skip_to_backtraces(self): """ Skips the "Additional Diagnostic Information" section. """ for line in self._file: #print line, if line.startswith("Thread 0"): # TODO: Push back? break def _parse_backtrace(self): """ """ lines = [] for line in self._file: line = line.rstrip() #print line if not line: break lines.append(line) return Backtrace(lines) if __name__ == "__main__": reports = [] for crash_report_filename in sys.argv[1:]: #print crash_report_filename reports.append(CrashReport(crash_report_filename)) #import pprint #pprint.pprint(reports[0].info) print "Total reports processed: ", len(reports) print from collections import defaultdict reports_by_type = defaultdict(list) for report in reports: reports_by_type[report.info["Exception Type"]].append(report) for exception_type, report_group in reports_by_type.items(): print print exception_type, "| Occurrences: ", len(report_group) for report in report_group: print print " ", report.info["Exception Codes"] for line_number in range(5): print " ", report.backtraces[0].lines[line_number]