diff --git a/scripts/wk/__init__.py b/scripts/wk/__init__.py index e24443d0..b6a11b56 100644 --- a/scripts/wk/__init__.py +++ b/scripts/wk/__init__.py @@ -4,6 +4,7 @@ from sys import version_info as version from wk import cfg +from wk import debug from wk import exe from wk import graph from wk import hw diff --git a/scripts/wk/debug.py b/scripts/wk/debug.py new file mode 100644 index 00000000..437ab0f8 --- /dev/null +++ b/scripts/wk/debug.py @@ -0,0 +1,45 @@ +"""WizardKit: Debug Functions""" +# pylint: disable=invalid-name +# vim: sts=2 sw=2 ts=2 + + +# Classes +class Debug(): + # pylint: disable=too-few-public-methods + """Object used when dumping debug data.""" + def method(self): + """Dummy method used to identify functions vs data.""" + + +# STATIC VARIABLES +DEBUG_CLASS = Debug() +METHOD_TYPE = type(DEBUG_CLASS.method) + + +# Functions +def generate_object_report(obj, indent=0): + """Generate debug report for obj, returns list.""" + report = [] + + # Dump object data + for name in dir(obj): + attr = getattr(obj, name) + + # Skip methods and private attributes + if isinstance(attr, METHOD_TYPE) or name.startswith('_'): + continue + + # Add attribute to report (expanded if necessary) + if isinstance(attr, dict): + report.append(f'{name}:') + for key, value in sorted(attr.items()): + report.append(f'{" "*(indent+1)}{key}: {str(value)}') + else: + report.append(f'{" "*indent}{name}: {str(attr)}') + + # Done + return report + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/scripts/wk/hw/diags.py b/scripts/wk/hw/diags.py index 285fa93d..b9d2470d 100644 --- a/scripts/wk/hw/diags.py +++ b/scripts/wk/hw/diags.py @@ -15,7 +15,7 @@ import time from collections import OrderedDict from docopt import docopt -from wk import cfg, exe, graph, log, net, std, tmux +from wk import cfg, debug, exe, graph, log, net, std, tmux from wk.hw import obj as hw_obj from wk.hw import sensors as hw_sensors @@ -266,8 +266,8 @@ class State(): # NOTE: Prime95 should be added first test_mprime_obj = hw_obj.Test(dev=self.cpu, label='Prime95') test_cooling_obj = hw_obj.Test(dev=self.cpu, label='Cooling') - self.cpu.tests[name] = test_mprime_obj - self.cpu.tests[name] = test_cooling_obj + self.cpu.tests[test_mprime_obj.label] = test_mprime_obj + self.cpu.tests[test_cooling_obj.label] = test_cooling_obj self.tests[name]['Objects'].append(test_mprime_obj) self.tests[name]['Objects'].append(test_cooling_obj) elif 'Disk' in name: @@ -308,6 +308,34 @@ class State(): text=' ', ) + def save_debug_reports(self): + """Save debug reports to disk.""" + LOG.info('Saving debug reports') + debug_dir = pathlib.Path(f'{self.log_dir}/debug') + if not debug_dir.exists(): + debug_dir.mkdir() + + # State (self) + with open(f'{debug_dir}/state.report', 'a') as _f: + _f.write('\n'.join(debug.generate_object_report(self))) + + # CPU/RAM + with open(f'{debug_dir}/cpu.report', 'a') as _f: + _f.write('\n'.join(debug.generate_object_report(self.cpu))) + _f.write('\n\n[Tests]') + for name, test in self.cpu.tests.items(): + _f.write(f'\n{name}:\n') + _f.write('\n'.join(debug.generate_object_report(test, indent=1))) + + # Disks + for disk in self.disks: + with open(f'{debug_dir}/disk_{disk.path.name}.report', 'a') as _f: + _f.write('\n'.join(debug.generate_object_report(disk))) + _f.write('\n\n[Tests]') + for name, test in disk.tests.items(): + _f.write(f'\n{name}:\n') + _f.write('\n'.join(debug.generate_object_report(test, indent=1))) + def update_progress_pane(self): """Update progress pane.""" report = [] @@ -1120,7 +1148,6 @@ def main(): # Init atexit.register(tmux.kill_all_panes) - #TODO: Add state/dev data dump debug function menu = build_menu(cli_mode=args['--cli'], quick_mode=args['--quick']) state = State() @@ -1235,6 +1262,7 @@ def print_countdown(proc, seconds): def run_diags(state, menu, quick_mode=False): """Run selected diagnostics.""" aborted = False + atexit.register(state.save_debug_reports) state.init_diags(menu) # Just return if no tests were selected @@ -1278,6 +1306,8 @@ def run_diags(state, menu, quick_mode=False): show_results(state) # Done + state.save_debug_reports() + atexit.unregister(state.save_debug_reports) if quick_mode: std.pause('Press Enter to exit...') else: