diff --git a/logging.py b/logging.py index 4cd36e5827d7b1d2c35a1575222d7e84647dbc76..9c134d5061a7ac914659e37d8c86f8cd8f3d9f40 100644 --- a/logging.py +++ b/logging.py @@ -14,12 +14,15 @@ import logging.config, pathlib, sys this = sys.modules[__name__] this.settings = None project_dir = pathlib.Path().absolute() -logging_directory = project_dir.joinpath('src/logs') -logging_class = 'logging.handlers.RotatingFileHandler' -logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. -logging_backup_count = 10 # Keep 10 log files before overwriting. +this.logging_directory = project_dir.joinpath('src/logs') +this.logging_class = 'logging.handlers.RotatingFileHandler' +this.logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. +this.logging_backup_count = 10 # Keep 10 log files before overwriting. +#region User Logging Settings +# These functions are separated to make logging modification easier for the end user. + def get_logging_settings(): """ Returns an instance of the logging settings dictionary. @@ -62,37 +65,37 @@ def get_logging_settings(): # Debug Level - To file. 'file_debug': { 'level': 'DEBUG', - 'class': logging_class, - 'filename': logging_directory.joinpath('debug.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('debug.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Info Level - To file. 'file_info': { 'level': 'INFO', - 'class': logging_class, - 'filename': logging_directory.joinpath('info.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('info.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Warn Level - To file. 'file_warn': { 'level': 'WARNING', - 'class': logging_class, - 'filename': logging_directory.joinpath('warn.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('warn.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Error Level - To file. 'file_error': { 'level': 'ERROR', - 'class': logging_class, - 'filename': logging_directory.joinpath('error.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('error.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, }, @@ -107,27 +110,79 @@ def get_logging_settings(): } -def init_logging(caller): +def set_new_log_levels(): + """ + Function for adding new logging levels. + """ + # Add new logging levels here. + pass + + +#endregion User Logging Settings + + +#region Logging Helper Functions + +def init_logging(caller, logging_dir=None, handler_class=None, max_file_bytes=None, log_backup_count=None): """ Initializes and returns an instance of the logger. :param caller: __name__ attribute of calling file. - :param initialize_settings: Boolean defined at top of file. + :param logging_dir: Optional override to change default logging directory. + :param handler_class: Optional override to change default logging handler. + :param max_file_bytes: Optional override to change default max log file size. + :param log_backup_count: Optional override to change default max count of log files. :return: Instance of logger, associated with calling file's __name__. """ + # Define settings, if not yet created. if this.settings is None: + + # Check for module variable overrides. + if logging_dir is not None: + # Validate input. + if not isinstance(logging_dir, pathlib.PurePath): + logging_dir = pathlib.Path(logging_dir).absolute() + # Set value. + this.logging_directory = logging_dir + + if handler_class is not None: + # Unsure of how to validate input. However, seems to error on bad input so probably okay. + this.logging_class = handler_class + + if max_file_bytes is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected max_file_bytes of type int. Got {0}.'.format(type(max_file_bytes))) + # Set value. + this.logging_max_bytes = max_file_bytes + + if log_backup_count is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected log_backup_count of type int. Got {0}.'.format(type(log_backup_count))) + # Set value. + this.logging_backup_count = log_backup_count + # Create logging folder if does not exist. - if not logging_directory.is_dir(): + if not this.logging_directory.is_dir(): print('Creating logging folders.') - logging_directory.mkdir() + this.logging_directory.mkdir() - # Add new logging levels here. + # Add new logging levels, as defined in method above. + set_new_log_levels() # Load dictionary of settings into logger. this.settings = get_logging_settings() logging.config.dictConfig(this.settings) - # Clear setup variable to prevent calling again on each file that imports logging. - initialize_settings = False + else: + if (logging_dir is not None or + handler_class is not None or + max_file_bytes is not None or + log_backup_count is not None + ): + raise RuntimeError( + 'One or more logging default overrides have been passed, but logging has already been initialized.' + ) return logging.getLogger(caller) @@ -178,3 +233,5 @@ def add_logging_level(level_name, level_num, method_name=None): setattr(logging, level_name, level_num) setattr(logging.getLoggerClass(), method_name, log_for_level) setattr(logging, method_name, log_to_root) + +#endregion Logging Helper Functions diff --git a/tests/src/logging.py b/tests/src/logging.py index 345cbbf303a2eb43e84d3c4d34e880a109a4d018..846407a90f31237ff98fc7506f38519022254a1e 100644 --- a/tests/src/logging.py +++ b/tests/src/logging.py @@ -14,12 +14,15 @@ import logging.config, pathlib, sys this = sys.modules[__name__] this.settings = None project_dir = pathlib.Path().absolute() -logging_directory = project_dir.joinpath('src/logs') -logging_class = 'logging.handlers.RotatingFileHandler' -logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. -logging_backup_count = 10 # Keep 10 log files before overwriting. +this.logging_directory = project_dir.joinpath('src/logs') +this.logging_class = 'logging.handlers.RotatingFileHandler' +this.logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. +this.logging_backup_count = 10 # Keep 10 log files before overwriting. +#region User Logging Settings +# These functions are separated to make logging modification easier for the end user. + def get_logging_settings(): """ Returns an instance of the logging settings dictionary. @@ -62,45 +65,45 @@ def get_logging_settings(): # Debug Level - To file. 'file_debug': { 'level': 'DEBUG', - 'class': logging_class, - 'filename': logging_directory.joinpath('debug.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('debug.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Info Level - To file. 'file_info': { 'level': 'INFO', - 'class': logging_class, - 'filename': logging_directory.joinpath('info.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('info.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Warn Level - To file. 'file_warn': { 'level': 'WARNING', - 'class': logging_class, - 'filename': logging_directory.joinpath('warn.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('warn.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Error Level - To file. 'file_error': { 'level': 'ERROR', - 'class': logging_class, - 'filename': logging_directory.joinpath('error.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('error.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, 'test_level': { 'level': 'TESTING', - 'class': logging_class, - 'filename': logging_directory.joinpath('test.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('test.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, }, @@ -115,28 +118,79 @@ def get_logging_settings(): } -def init_logging(caller): +def set_new_log_levels(): + """ + Function for adding new logging levels. + """ + # Add new logging levels here. + add_logging_level('TESTING', 25) + + +#endregion User Logging Settings + + +#region Logging Helper Functions + +def init_logging(caller, logging_dir=None, handler_class=None, max_file_bytes=None, log_backup_count=None): """ Initializes and returns an instance of the logger. :param caller: __name__ attribute of calling file. - :param initialize_settings: Boolean defined at top of file. + :param logging_dir: Optional override to change default logging directory. + :param handler_class: Optional override to change default logging handler. + :param max_file_bytes: Optional override to change default max log file size. + :param log_backup_count: Optional override to change default max count of log files. :return: Instance of logger, associated with calling file's __name__. """ + # Define settings, if not yet created. if this.settings is None: + + # Check for module variable overrides. + if logging_dir is not None: + # Validate input. + if not isinstance(logging_dir, pathlib.PurePath): + logging_dir = pathlib.Path(logging_dir).absolute() + # Set value. + this.logging_directory = logging_dir + + if handler_class is not None: + # Unsure of how to validate input. However, seems to error on bad input so probably okay. + this.logging_class = handler_class + + if max_file_bytes is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected max_file_bytes of type int. Got {0}.'.format(type(max_file_bytes))) + # Set value. + this.logging_max_bytes = max_file_bytes + + if log_backup_count is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected log_backup_count of type int. Got {0}.'.format(type(log_backup_count))) + # Set value. + this.logging_backup_count = log_backup_count + # Create logging folder if does not exist. - if not logging_directory.is_dir(): + if not this.logging_directory.is_dir(): print('Creating logging folders.') - logging_directory.mkdir() + this.logging_directory.mkdir() - # Add new logging levels here. - add_logging_level('TESTING', 25) + # Add new logging levels, as defined in method above. + set_new_log_levels() # Load dictionary of settings into logger. this.settings = get_logging_settings() logging.config.dictConfig(this.settings) - # Clear setup variable to prevent calling again on each file that imports logging. - initialize_settings = False + else: + if (logging_dir is not None or + handler_class is not None or + max_file_bytes is not None or + log_backup_count is not None + ): + raise RuntimeError( + 'One or more logging default overrides have been passed, but logging has already been initialized.' + ) return logging.getLogger(caller) @@ -187,3 +241,5 @@ def add_logging_level(level_name, level_num, method_name=None): setattr(logging, level_name, level_num) setattr(logging.getLoggerClass(), method_name, log_for_level) setattr(logging, method_name, log_to_root) + +#endregion Logging Helper Functions diff --git a/tests/src/submodule_test/src/logging.py b/tests/src/submodule_test/src/logging.py index 3c107bbee8ffd324aa29802153478c585efa0768..bf85e784a0e938e987c9fbb2665e6cbb6526a650 100644 --- a/tests/src/submodule_test/src/logging.py +++ b/tests/src/submodule_test/src/logging.py @@ -14,12 +14,15 @@ import logging.config, pathlib, sys this = sys.modules[__name__] this.settings = None project_dir = pathlib.Path().absolute() -logging_directory = project_dir.joinpath('src/logs') -logging_class = 'logging.handlers.RotatingFileHandler' -logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. -logging_backup_count = 10 # Keep 10 log files before overwriting. +this.logging_directory = project_dir.joinpath('src/logs') +this.logging_class = 'logging.handlers.RotatingFileHandler' +this.logging_max_bytes = 1024 * 1024 * 10 # Max log file size of 10 MB. +this.logging_backup_count = 10 # Keep 10 log files before overwriting. +#region User Logging Settings +# These functions are separated to make logging modification easier for the end user. + def get_logging_settings(): """ Returns an instance of the logging settings dictionary. @@ -62,45 +65,45 @@ def get_logging_settings(): # Debug Level - To file. 'file_debug': { 'level': 'DEBUG', - 'class': logging_class, - 'filename': logging_directory.joinpath('debug.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('debug.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Info Level - To file. 'file_info': { 'level': 'INFO', - 'class': logging_class, - 'filename': logging_directory.joinpath('info.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('info.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Warn Level - To file. 'file_warn': { 'level': 'WARNING', - 'class': logging_class, - 'filename': logging_directory.joinpath('warn.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('warn.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, # Error Level - To file. 'file_error': { 'level': 'ERROR', - 'class': logging_class, - 'filename': logging_directory.joinpath('error.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('error.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, 'submodule_level': { 'level': 'SUBMODULE', - 'class': logging_class, - 'filename': logging_directory.joinpath('test.log'), - 'maxBytes': logging_max_bytes, - 'backupCount': logging_backup_count, + 'class': this.logging_class, + 'filename': this.logging_directory.joinpath('test.log'), + 'maxBytes': this.logging_max_bytes, + 'backupCount': this.logging_backup_count, 'formatter': 'standard', }, }, @@ -115,28 +118,79 @@ def get_logging_settings(): } -def init_logging(caller): +def set_new_log_levels(): + """ + Function for adding new logging levels. + """ + # Add new logging levels here. + add_logging_level('SUBMODULE', 26) + + +#endregion User Logging Settings + + +#region Logging Helper Functions + +def init_logging(caller, logging_dir=None, handler_class=None, max_file_bytes=None, log_backup_count=None): """ Initializes and returns an instance of the logger. :param caller: __name__ attribute of calling file. - :param initialize_settings: Boolean defined at top of file. + :param logging_dir: Optional override to change default logging directory. + :param handler_class: Optional override to change default logging handler. + :param max_file_bytes: Optional override to change default max log file size. + :param log_backup_count: Optional override to change default max count of log files. :return: Instance of logger, associated with calling file's __name__. """ + # Define settings, if not yet created. if this.settings is None: + + # Check for module variable overrides. + if logging_dir is not None: + # Validate input. + if not isinstance(logging_dir, pathlib.PurePath): + logging_dir = pathlib.Path(logging_dir).absolute() + # Set value. + this.logging_directory = logging_dir + + if handler_class is not None: + # Unsure of how to validate input. However, seems to error on bad input so probably okay. + this.logging_class = handler_class + + if max_file_bytes is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected max_file_bytes of type int. Got {0}.'.format(type(max_file_bytes))) + # Set value. + this.logging_max_bytes = max_file_bytes + + if log_backup_count is not None: + # Validate input. + if not isinstance(max_file_bytes, int): + raise TypeError('Expected log_backup_count of type int. Got {0}.'.format(type(log_backup_count))) + # Set value. + this.logging_backup_count = log_backup_count + # Create logging folder if does not exist. - if not logging_directory.is_dir(): + if not this.logging_directory.is_dir(): print('Creating logging folders.') - logging_directory.mkdir() + this.logging_directory.mkdir() - # Add new logging levels here. - add_logging_level('SUBMODULE', 26) + # Add new logging levels, as defined in method above. + set_new_log_levels() # Load dictionary of settings into logger. this.settings = get_logging_settings() logging.config.dictConfig(this.settings) - # Clear setup variable to prevent calling again on each file that imports logging. - initialize_settings = False + else: + if (logging_dir is not None or + handler_class is not None or + max_file_bytes is not None or + log_backup_count is not None + ): + raise RuntimeError( + 'One or more logging default overrides have been passed, but logging has already been initialized.' + ) return logging.getLogger(caller) @@ -164,9 +218,9 @@ def add_logging_level(level_name, level_num, method_name=None): # Log level already set with same values. Skip setting. return None elif (hasattr(logging, level_name) or - hasattr(logging, method_name) or - hasattr(logging.getLoggerClass(), method_name) or - orig_log_level_name != 'Level {0}'.format(level_num) + hasattr(logging, method_name) or + hasattr(logging.getLoggerClass(), method_name) or + orig_log_level_name != 'Level {0}'.format(level_num) ): # Log level partially defined with some values. Raise error. raise AttributeError('Level "{0}: {1}" already defined in logging module, but values do not match.'.format( @@ -187,3 +241,5 @@ def add_logging_level(level_name, level_num, method_name=None): setattr(logging, level_name, level_num) setattr(logging.getLoggerClass(), method_name, log_for_level) setattr(logging, method_name, log_to_root) + +#endregion Logging Helper Functions