Spaces:
No application file
No application file
| # -*- coding: utf-8 -*- | |
| # Logging Class | |
| # | |
| # @ Fabian Hörst, fabian.hoerst@uk-essen.de | |
| # Institute for Artifical Intelligence in Medicine, | |
| # University Medicine Essen | |
| import datetime | |
| from typing import Literal, Union | |
| from pathlib import Path | |
| import logging | |
| import logging.handlers | |
| import os | |
| import sys | |
| class Logger: | |
| """Initialize a Logger for sys-logging and RotatingFileHandler-logging by using python logging module. | |
| The logger can be used out of the box without any changes, but is also adaptable for specific use cases. | |
| In basic configuration, just the log level must be provided. If log_dir is provided, another handler object is created | |
| logging into a file into the log_dir directory. The filename can be changes by using comment, which basically is the filename. | |
| To create different log files with specific timestamp set 'use_timestamp' = True. This adds an additional timestamp to the filename. | |
| Args: | |
| level (Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]): Logger.level | |
| log_dir (Union[Path, str], optional): Path to save logfile in. Defaults to None. | |
| comment (str, optional): additional comment for save file. Defaults to 'logs'. | |
| formatter (str, optional): Custom formatter. Defaults to None. | |
| use_timestamp (bool, optional): Using timestamp for time-logging. Defaults to False. | |
| file_level (Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], optional): Set Logger.level. for output file. | |
| Can be useful if a different logging level should be used for terminal output and logging file. | |
| If no level is selected, file level logging is the same as for console. Defaults to None. | |
| """ | |
| def __init__( | |
| self, | |
| level: Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], | |
| log_dir: Union[Path, str] = None, | |
| comment: str = "logs", | |
| formatter: str = None, | |
| use_timestamp: bool = False, | |
| file_level: Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] = None, | |
| ) -> None: | |
| self.level = level | |
| self.comment = comment | |
| self.log_parent_dir = log_dir | |
| self.use_timestamp = use_timestamp | |
| if formatter is None: | |
| self.formatter = "%(asctime)s [%(levelname)s] - %(message)s" | |
| else: | |
| self.formatter = formatter | |
| if file_level is None: | |
| self.file_level = level | |
| else: | |
| self.file_level = file_level | |
| def create_handler(self, logger: logging.Logger) -> None: | |
| """Create logging handler for sys output and rotating files in parent_dir. | |
| Args: | |
| logger (logging.Logger): The Logger | |
| """ | |
| log_handlers = {"StreamHandler": logging.StreamHandler(stream=sys.stdout)} | |
| fh_formatter = logging.Formatter(f"{self.formatter}") | |
| log_handlers["StreamHandler"].setLevel(self.level) | |
| if self.log_parent_dir is not None: | |
| log_parent_dir = Path(self.log_parent_dir) | |
| if self.use_timestamp: | |
| log_name = f'{datetime.datetime.now().strftime("%Y-%m-%dT%H%M%S")}_{self.comment}.log' | |
| else: | |
| log_name = f"{self.comment}.log" | |
| log_parent_dir.mkdir(parents=True, exist_ok=True) | |
| should_roll_over = os.path.isfile(log_parent_dir / log_name) | |
| log_handlers["FileHandler"] = logging.handlers.RotatingFileHandler( | |
| log_parent_dir / log_name, backupCount=5 | |
| ) | |
| if should_roll_over: # log already exists, roll over! | |
| log_handlers["FileHandler"].doRollover() | |
| log_handlers["FileHandler"].setLevel(self.file_level) | |
| for handler in log_handlers.values(): | |
| handler.setFormatter(fh_formatter) | |
| logger.addHandler(handler) | |
| def create_logger(self) -> logging.Logger: | |
| """Create the logger | |
| Returns: | |
| Logger: The logger to be used. | |
| """ | |
| logger = logging.getLogger("__main__") | |
| logger.addHandler(logging.NullHandler()) | |
| logger.setLevel( | |
| "DEBUG" | |
| ) # set to debug because each handler level must be equal or lower | |
| self.create_handler(logger) | |
| return logger | |