#!/usr/bin/python3 # # rpicam-apps bug report generator. # Copyright (C) 2021, Raspberry Pi Ltd. # import argparse from datetime import datetime import select import subprocess import sys import time class Report: def __init__(self, id, file): self._id = id self._cmds = [] self._strs = [] self._file = file def __run_cmd(self, cmd): print(f"** {cmd} **", file=self._file) try: p = subprocess.run( cmd, text=True, check=False, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) print(p.stdout, file=self._file) except RuntimeError as e: print(f"Error: {e}", file=self._file) def add_cmd(self, c): self._cmds.append(c) def add_str(self, s): self._strs.append(s) def exec(self): print(f"{'-' * 80}\n{self._id}\n{'-' * 80}", file=self._file) for c in self._cmds: self.__run_cmd(c) for s in self._strs: print(s, file=self._file) def run_prog(cmd, t): cmd = cmd.split(" ") out = [] try: start = time.time() p = subprocess.Popen( cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, errors="ignore", ) poll = select.poll() poll.register(p.stdout, select.POLLIN) while p.poll() is None: if poll.poll(0): line = p.stdout.readline() print(line, end="", flush=True) out.append(line) if (t != 0) and (time.time() - start > t): p.kill() out = out + p.communicate()[0].splitlines(keepends=True) out.append("Error: ***** TIMEOUT *****") break except KeyboardInterrupt: p.kill() out = out + p.communicate()[0].splitlines(keepends=True) out.append("Error: ***** INTERRUPT *****") p.wait() return "".join(out) if __name__ == "__main__": parser = argparse.ArgumentParser(description="rpicam-apps Bug Report Generator") parser.add_argument( "-o", help="Report filename", type=str, default="bug-report.txt" ) parser.add_argument( "-t", help="Timeout (seconds) for the command to run. A value of 0 \ disables the timeout.", type=float, default=0, ) parser.add_argument( "-c", help='Command to run, e.g. -c "rpicam-still -t 1000 -o test.jpg"', type=str, ) args = parser.parse_args() # This is the app the user is actually running. app = "rpicam-hello" if args.c: app = args.c.split(" ")[0] # Can we identify the app? If not, use rpicam-hello for version checks. if not any( [ s in app for s in [ "rpicam-still", "rpicam-vid", "rpicam-hello", "rpicam-raw", "rpicam-jpeg", ] ] ): app = "rpicam-hello" reports = [] with open(args.o, "wt") as file: title = Report("rpicam-apps Bug Report", file) title.add_str(f"Date: {datetime.now().strftime('%d-%m-%Y (%H:%M:%S)')}") title.add_str(f"Command: {' '.join(sys.argv)}\n") reports.append(title) hwinfo = Report("Hardware information", file) hwinfo.add_cmd("hostname") hwinfo.add_cmd("cat /proc/cpuinfo") reports.append(hwinfo) config = Report("Configuration", file) config.add_cmd("cat /boot/firmware/cmdline.txt") config.add_cmd("cat /boot/firmware/config.txt") reports.append(config) logs = Report("Logs", file) logs.add_cmd("dmesg") logs.add_cmd("sudo vclog log --msg") logs.add_cmd("sudo vclog log --assert") reports.append(logs) mem = Report("Memory", file) mem.add_cmd("cat /proc/meminfo") mem.add_cmd("sudo cat /sys/kernel/debug/dma_buf/bufinfo") mem.add_cmd("sudo cat /sys/kernel/debug/vcsm-cma/state") reports.append(mem) media = Report("Media Devices", file) for i in range(5): media.add_cmd(f"media-ctl -d {i} -p") reports.append(media) # Get the camera list with the same program specified in the run command cam = Report("Cameras", file) cam.add_cmd(f"{app} --list-cameras") reports.append(cam) # Get the version with the same program specified in the run command ver = Report("Versions", file) ver.add_cmd("uname -a") ver.add_cmd("cat /etc/os-release") ver.add_cmd("vcgencmd version") ver.add_cmd(f"{app} --version") reports.append(ver) # Run the actual application before executing the reports! if args.c: cmd_out = run_prog(args.c, args.t) # Report for the command output cmd = Report(args.c, file) cmd.add_str(cmd_out) reports.append(cmd) for r in reports: r.exec() print(f"\nBug report generated to {args.o}") print("Please upload this file when you create a new bug report at:") print("https://github.com/raspberrypi/rpicam-apps/issues/")