| | |
| | """Contains the base class for logging. |
| | |
| | Basically, this is an interface bridging the program and the local file system. |
| | A logger is able to log wrapped message onto the screen and a log file. |
| | """ |
| |
|
| | import logging |
| |
|
| | __all__ = ['BaseLogger'] |
| |
|
| |
|
| | class BaseLogger(object): |
| | """Defines the base logger. |
| | |
| | A logger should have the following members: |
| | |
| | (1) logger: The logger to record message. |
| | (2) pbar: The progressive bar (shown on the screen only). |
| | (3) pbar_kwargs: The arguments for the progressive bar. |
| | (4) file_stream: The stream to log messages into if needed. |
| | |
| | A logger should have the following functions: |
| | |
| | (1) log(): The base function to log message. |
| | (2) debug(): The function to log message with `DEBUG` level. |
| | (3) info(): The function to log message with `INFO` level. |
| | (4) warning(): The function to log message with `WARNING` level. |
| | (5) warn(): Same as function `warning()`. |
| | (6) error(): The function to log message with `ERROR` level. |
| | (7) exception(): The function to log message with exception information. |
| | (8) critical(): The function to log message with `CRITICAL` level. |
| | (9) fatal(): Same as function `critical()`. |
| | (10) print(): The function to print the message without any decoration. |
| | (11) init_pbar(): The function to initialize the progressive bar. |
| | (12) add_pbar_task(): The function to add a task to the progressive bar. |
| | (13) update_pbar(): The function to update the progressive bar. |
| | (14) close_pbar(): The function to close the progressive bar. |
| | |
| | The logger will record log message both on screen and to file. |
| | |
| | Args: |
| | logger_name: Unique name for the logger. (default: `logger`) |
| | logfile: Path to the log file. If set as `None`, the file stream |
| | will be skipped. (default: `None`) |
| | screen_level: Minimum level of message to log onto screen. |
| | (default: `logging.INFO`) |
| | file_level: Minimum level of message to log into file. |
| | (default: `logging.DEBUG`) |
| | indent_space: Number of spaces between two adjacent indent levels. |
| | (default: 4) |
| | verbose_log: Whether to log verbose message. (default: False) |
| | """ |
| |
|
| | def __init__(self, |
| | logger_name='logger', |
| | logfile=None, |
| | screen_level=logging.INFO, |
| | file_level=logging.DEBUG, |
| | indent_space=4, |
| | verbose_log=False): |
| | self.logger_name = logger_name |
| | self.logfile = logfile |
| | self.screen_level = screen_level |
| | self.file_level = file_level |
| | self.indent_space = indent_space |
| | self.verbose_log = verbose_log |
| |
|
| | self.logger = None |
| | self.pbar = None |
| | self.pbar_kwargs = None |
| | self.file_stream = None |
| |
|
| | self.warn = self.warning |
| | self.fatal = self.critical |
| |
|
| | def __del__(self): |
| | self.close() |
| |
|
| | def close(self): |
| | """Closes the logger.""" |
| | if self.file_stream is not None: |
| | self.file_stream.close() |
| |
|
| | @property |
| | def name(self): |
| | """Returns the class name of the logger.""" |
| | return self.__class__.__name__ |
| |
|
| | |
| | def wrap_message(self, message, indent_level=0): |
| | """Wraps the message with indent.""" |
| | if message is None: |
| | message = '' |
| | assert isinstance(message, str) |
| | assert isinstance(indent_level, int) and indent_level >= 0 |
| | if message == '': |
| | return '' |
| | return ' ' * (indent_level * self.indent_space) + message |
| |
|
| | def _log(self, message, **kwargs): |
| | """Logs wrapped message.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _debug(self, message, **kwargs): |
| | """Logs wrapped message with `DEBUG` level.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _info(self, message, **kwargs): |
| | """Logs wrapped message with `INFO` level.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _warning(self, message, **kwargs): |
| | """Logs wrapped message with `WARNING` level.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _error(self, message, **kwargs): |
| | """Logs wrapped message with `ERROR` level.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _exception(self, message, **kwargs): |
| | """Logs wrapped message with exception information.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _critical(self, message, **kwargs): |
| | """Logs wrapped message with `CRITICAL` level.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def _print(self, *messages, **kwargs): |
| | """Prints wrapped message without any decoration.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def log(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._log(message, **kwargs) |
| |
|
| | def debug(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with `DEBUG` level. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._debug(message, **kwargs) |
| |
|
| | def info(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with `INFO` level. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._info(message, **kwargs) |
| |
|
| | def warning(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with `WARNING` level. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._warning(message, **kwargs) |
| |
|
| | def error(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with `ERROR` level. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._error(message, **kwargs) |
| |
|
| | def exception(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with exception information. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._exception(message, **kwargs) |
| |
|
| | def critical(self, message, indent_level=0, is_verbose=False, **kwargs): |
| | """Logs message with `CRITICAL` level. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | message = self.wrap_message(message, indent_level=indent_level) |
| | self._critical(message, **kwargs) |
| |
|
| | def print(self, *messages, indent_level=0, is_verbose=False, **kwargs): |
| | """Prints message without any decoration. |
| | |
| | The message is wrapped with indent, and will be disabled if `is_verbose` |
| | is set as `True`. |
| | """ |
| | if is_verbose and not self.verbose_log: |
| | return |
| | new_messages = [] |
| | for message in messages: |
| | new_messages.append( |
| | self.wrap_message(message, indent_level=indent_level)) |
| | self._print(*new_messages, **kwargs) |
| |
|
| | |
| | def init_pbar(self, leave=False): |
| | """Initializes the progressive bar. |
| | |
| | Args: |
| | leave: Whether to leave the trace of the progressive bar. |
| | (default: False) |
| | """ |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def add_pbar_task(self, name, total, **kwargs): |
| | """Adds a task to the progressive bar. |
| | |
| | Args: |
| | name: Name of the added task. |
| | total: Total number of steps (samples) contained in the task. |
| | **kwargs: Additional arguments. |
| | |
| | Returns: |
| | Task ID. |
| | """ |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def update_pbar(self, task_id, advance=1): |
| | """Updates the progressive bar. |
| | |
| | Args: |
| | task_id: ID of the task to update. |
| | advance: Number of steps advanced onto the target task. (default: 1) |
| | """ |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|
| | def close_pbar(self): |
| | """Closes the progress bar.""" |
| | raise NotImplementedError('Should be implemented in derived class!') |
| |
|