diff --git a/auxilary.py b/auxilary.py index ec7dc2f..be1b3a8 100644 --- a/auxilary.py +++ b/auxilary.py @@ -18,6 +18,38 @@ class ConfigFile(): with open(self._path, 'w') as f: yaml.dump(self._dict, f, default_flow_style=False) +class async: + def __init__(self, daemon=False): + self._daemon = daemon + + def __call__(self, f): + def wrapper(*args, **kwargs): + t = Thread(target=f, daemon=self._daemon, args=args, kwargs=kwargs) + t.start() + return wrapper + +class CountdownTimer(Thread): + def __init__(self, countdownSeconds, action, sound=None): + self._stopper = Event() + + def countdown(): + for i in range(countdownSeconds, 0, -1): + if self._stopper.isSet(): + return None + if sound and i < countdownSeconds: + sound.play() + time.sleep(1) + action() + + super().__init__(target=countdown, daemon=True) + self.start() + + def stop(self): + self._stopper.set() + + def __del__(self): + self.stop() + def freeBusyPath(path, logger=None): # check if any other processes are using file path # if found, politely ask them to exit, else nuke them @@ -50,34 +82,5 @@ def freeBusyPath(path, logger=None): logger.warning('Failed to terminate PID %s. Sending SIGKILL', p.pid) p.kill() -class async: - def __init__(self, daemon=False): - self._daemon = daemon - - def __call__(self, f): - def wrapper(*args, **kwargs): - t = Thread(target=f, daemon=self._daemon, args=args, kwargs=kwargs) - t.start() - return wrapper - -class CountdownTimer(Thread): - def __init__(self, countdownSeconds, action, sound=None): - self._stopper = Event() - - def countdown(): - for i in range(countdownSeconds, 0, -1): - if self._stopper.isSet(): - return None - if sound and i < countdownSeconds: - sound.play() - time.sleep(1) - action() - - super().__init__(target=countdown, daemon=True) - self.start() - - def stop(self): - self._stopper.set() - - def __del__(self): - self.stop() +def fallbackLogger(module, loglevel, msg): + print('[{}] [{}] Logger not initialized, this will only go to console:\n{}'.format(module, loglevel, msg)) diff --git a/main.py b/main.py index a0cec71..9ed5b3a 100755 --- a/main.py +++ b/main.py @@ -5,6 +5,11 @@ import RPi.GPIO as GPIO from queue import Queue from multiprocessing.managers import BaseManager +from auxilary import fallbackLogger + +def printTrace(t): + fallbackLogger(__name__, 'CRITICAL', t) + def clean(): GPIO.cleanup() @@ -12,17 +17,22 @@ def clean(): stateMachine.__del__() except NameError: pass - + + # TODO: this part is really wordy and makes me sad try: logger.info('Terminated root process - PID: %s', os.getpid()) logger.stop() except NameError: pass + except Exception: + printTrace(traceback.format_exc()) try: manager.__del__() # kill process 2 except NameError: pass + except Exception: + printTrace(traceback.format_exc()) def sigtermHandler(signum, stackFrame): logger.info('Caught SIGTERM') @@ -44,7 +54,7 @@ if __name__ == '__main__': GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) - + manager = ResourceManager() manager.start() # Child process 1 @@ -58,7 +68,7 @@ if __name__ == '__main__': from stateMachine import StateMachine stateMachine = StateMachine() - + # TODO: segfaults are annoying :( #~ signal.signal(signal.SIGSEGV, sig_handler) signal.signal(signal.SIGTERM, sigtermHandler) @@ -67,7 +77,7 @@ if __name__ == '__main__': time.sleep(31536000) except Exception: - t = 'Exception caught:\n' + traceback.format_exc() + t = traceback.format_exc() try: criticalError(t) @@ -77,6 +87,7 @@ if __name__ == '__main__': try: logger.critical(t) except NameError: - print('[__main__] [CRITICAL] Logger not initialized, using print for console output:\n' + t) - + printTrace(t) + + finally: clean() diff --git a/sharedLogging.py b/sharedLogging.py index ac2e44c..bc690c9 100644 --- a/sharedLogging.py +++ b/sharedLogging.py @@ -1,7 +1,9 @@ -import logging, os +import logging, os, sys from subprocess import run, PIPE, CalledProcessError from logging.handlers import TimedRotatingFileHandler, QueueListener, QueueHandler +from auxilary import fallbackLogger + def SlaveLogger(name, level, queue): logger = logging.getLogger(name) logger.setLevel(getattr(logging, level)) @@ -29,8 +31,12 @@ class GlusterFS(): try: run(cmd, check=True, stdout=PIPE, stderr=PIPE) except CalledProcessError as e: - print(e.stderr.decode('ascii').rstrip()) - + # we assume that this will only get thrown when the logger is not + # active, so use fallback to get the explicit mount errors + stderr=e.stderr.decode('ascii').rstrip() + fallbackLogger(__name__, 'CRITICAL', stderr) + sys.exit() + class MasterLogger(): def __init__(self, name, level, queue): mountpoint = '/mnt/glusterfs/pyledriver'