diff --git a/src/helpers.py b/src/helpers.py index 3251b5d298fcba60587e2efb43f5e7ec575f398b..12ec837bfcc14753fb7a90ac34f4499f47cb485d 100644 --- a/src/helpers.py +++ b/src/helpers.py @@ -222,28 +222,56 @@ def dict_pop(dict_orig: Dict, pop_keys): class Logger: + """ + Basic logger class to unify all logging outputs. Logs are saved in local file and returned to std output. In default + settings, logging level of file logger is DEBUG, logging level of stream logger is INFO. Class must be imported + and initialised in starting script, all subscripts should log with logging.info(), debug, ... + """ - def __init__(self, log_path=None): + def __init__(self, log_path=None, level_file=logging.DEBUG, level_stream=logging.INFO): - if not log_path: - log_path = os.path.dirname(sys.modules["__main__"].__file__) - log_path = os.path.join(log_path, "logging") - if not os.path.exists(log_path): - os.makedirs(log_path) - runtime = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime()) - log_file = os.path.join(log_path, f'logging_{runtime}.log') + # define shared logger format + self.formatter = '%(asctime)s - %(levelname)s: %(message)s [%(filename)s:%(funcName)s:%(lineno)s]' - formatter = '%(asctime)s - %(levelname)s: %(message)s [%(filename)s:%(funcName)s:%(lineno)s]' - logging.basicConfig(level=logging.DEBUG, - format=formatter, + # set log path + log_file = self.setup_logging_path(log_path) + # set root logger as file handler + logging.basicConfig(level=level_file, + format=self.formatter, filename=log_file, filemode='a') - # define a Handler which writes INFO messages or higher to the sys.stderr + # add stream handler to the root logger + logging.getLogger('').addHandler(self.logger_console(level_stream)) + + @staticmethod + def setup_logging_path(path: str = None): + """ + Check if given path exists and creates if not. If path is None, use path from main. The logging file is named + like `logging_<runtime>.log` where runtime=`%Y-%m-%d_%H-%M-%S` of current run. + :param path: path to logfile + :return: path of logfile + """ + if not path: # set default path + path = os.path.dirname(sys.modules["__main__"].__file__) + path = os.path.join(path, "logging") + if not os.path.exists(path): + os.makedirs(path) + runtime = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime()) + log_file = os.path.join(path, f'logging_{runtime}.log') + return log_file + + def logger_console(self, level: int): + """ + Defines a stream handler which writes messages of given level or higher to std out + :param level: logging level as integer, e.g. logging.DEBUG or 10 + :return: defines stream handler + """ + # define Handler console = logging.StreamHandler() - console.setLevel(logging.INFO) + # set level of Handler + console.setLevel(level) # set a format which is simpler for console use - formatter = logging.Formatter(formatter) + formatter = logging.Formatter(self.formatter) # tell the handler to use this format console.setFormatter(formatter) - # add the handler to the root logger - logging.getLogger('').addHandler(console) + return console