def exception_hook(cls, etype, value, tb): """ sys.excepthook will call this method """ import traceback # Print exception traceback.print_exception(etype, value, tb) # Log exception stacktrace_msg = ''.join(traceback.format_tb(tb)) if etype: exception_msg = '{0}: {1}'.format(etype, value) else: exception_msg = 'Exception: {}'.format(value) LOGGER.critical(stacktrace_msg) LOGGER.critical(exception_msg) # Write to exception log file exception_file_name = datetime.now().strftime( 'RenderKnecht_Exception_%Y-%m-%d_%H%M%S.log') exception_file = Path(get_settings_dir()) / exception_file_name with open(exception_file, 'w') as f: traceback.print_exception(etype, value, tb, file=f) # Inform GUI of exception if QApplication set if cls.app: gui_msg = f'{stacktrace_msg}\n{exception_msg}' cls.send_exception_signal(gui_msg)
def get_settings_path() -> str: _settings_dir = get_settings_dir() _settings_file = os.path.join(_settings_dir, SETTINGS_FILE) return _settings_file
def setup_logging(logging_queue, overwrite_level: str=None): # Track calls to this method print('Logging setup called: ', Path(sys._getframe().f_back.f_code.co_filename).name, sys._getframe().f_back.f_code.co_name) if FROZEN: log_level = 'INFO' else: log_level = 'DEBUG' if overwrite_level: log_level = overwrite_level log_file_path = Path(get_settings_dir()) / Path(LOG_FILE_NAME) log_conf = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' }, 'simple': { 'format': '%(asctime)s %(name)s %(levelname)s: %(message)s', 'datefmt': '%d.%m.%Y %H:%M' }, 'guiFormatter': { 'format': '%(name)s %(levelname)s: %(message)s', 'datefmt': '%d.%m.%Y %H:%M', }, 'file_formatter': { 'format': '%(asctime)s.%(msecs)03d %(name)s %(levelname)s: %(message)s', 'datefmt': '%d.%m.%Y %H:%M:%S' }, }, 'handlers': { 'console': { 'level': log_level, 'class': 'logging.StreamHandler', 'stream': 'ext://sys.stdout', 'formatter': 'simple' }, 'guiHandler': { 'level': log_level, 'class': 'logging.NullHandler', 'formatter': 'simple', }, 'file': { 'level': log_level, 'class': 'logging.handlers.RotatingFileHandler', 'filename': log_file_path.absolute().as_posix(), 'maxBytes': 5000000, 'backupCount': 4, 'formatter': 'file_formatter', }, 'queueHandler': { 'level': log_level, 'class': 'logging.handlers.QueueHandler', # From Python 3.7.1 defining a formatter will output the formatter of the queueHandler # as well as the re-routed handler formatter eg. console -> queue listener 'queue': logging_queue }, }, 'loggers': { # Main logger, these handlers will be moved to the QueueListener MAIN_LOGGER_NAME: { 'handlers': ['file', 'guiHandler', 'console'], 'propagate': False, 'level': log_level, }, # Log Window Logger 'gui_logger': { 'handlers': ['guiHandler', 'queueHandler'], 'propagate': False, 'level': 'INFO' }, # Module loggers '': { 'handlers': ['queueHandler'], 'propagate': False, 'level': log_level, } } } logging.config.dictConfig(log_conf)