blob: 9e3983bc704a6a2e753ad3c1d2b8b019af6ea96b [file] [log] [blame]
"""
Finds and prints the crash report associated with a specific (binary filename, process id).
Waits (max_wait_time/attempts_remaining) between retries.
By default, max_wait_time=5 and retry_count=10, which results in a total wait time of ~15s
Errors if the report cannot be found after `retry_count` retries.
"""
import sys, os, argparse, re, glob, shutil, time
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--pid', type=str, required=True, help='The process id of the process that crashed')
parser.add_argument('--binary-filename', type=str, required=True, help='The name of the file that crashed')
parser.add_argument('--retry-count', type=int, nargs='?', default=10, help='The number of retries to make')
parser.add_argument('--max-wait-time', type=float, nargs='?', default=5.0, help='The max amount of seconds to wait between tries')
parser.add_argument('--dir', nargs='?', type=str, default="~/Library/Logs/DiagnosticReports", help='The directory to look for the crash report')
parser.add_argument('--outfile', nargs='?', type=argparse.FileType('r'), default=sys.stdout, help='Where to write the result')
args = parser.parse_args()
assert args.pid, "pid can't be empty"
assert args.binary_filename, "binary-filename can't be empty"
os.chdir(os.path.expanduser(args.dir))
output_report_with_retries(args.outfile, args.pid.strip(), args.binary_filename, args.retry_count, args.max_wait_time)
def output_report_with_retries(outfile, pid, filename, attempts_remaining, max_wait_time):
report_name = find_report_in_cur_dir(pid, filename)
if report_name:
with open(report_name, "r") as f:
shutil.copyfileobj(f, outfile)
return
elif(attempts_remaining > 0):
# As the number of attempts remaining decreases, increase the number of seconds waited
# if the max wait time is 2s and there are 10 attempts remaining, wait .2 seconds.
# if the max wait time is 2s and there are 2 attempts remaining, wait 1 second.
time.sleep(max_wait_time / attempts_remaining)
output_report_with_retries(outfile, pid, filename, attempts_remaining - 1, max_wait_time)
else:
raise RuntimeError("Report not found for ({}, {}).".format(filename, pid))
def find_report_in_cur_dir(pid, filename):
for report_name in sorted(glob.glob("{}_*.crash".format(filename)), reverse=True):
# parse out pid from first line of report
# `Process: filename [pid]``
with open(report_name) as cur_report:
pattern = re.compile(r'Process: *{} \[([0-9]*)\]'.format(filename))
cur_report_pid = pattern.search(cur_report.readline()).group(1)
assert cur_report_pid and cur_report_pid.isdigit()
if cur_report_pid == pid:
return report_name
# did not find the crash report
return None
if __name__ == '__main__':
main()