Source code for jacinle.logging

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File   : logging.py
# Author : Jiayuan Mao
# Email  : maojiayuan@gmail.com
# Date   : 01/17/2017
#
# This file is part of Jacinle.
# Distributed under terms of the MIT license.

import logging
import functools
import sys

__all__ = ['set_output_file', 'set_logger_output_file', 'set_default_level', 'get_logger']

_g_default_level = logging.INFO
_g_all_loggers = []


[docs] def set_output_file(fout, mode='a'): """The the output file for all loggers. Args: fout: the output file path. mode: the mode to open the file. """ if isinstance(fout, str): fout = open(fout, mode) JacLogFormatter.log_fout = fout
[docs] def set_logger_output_file(fout, mode='a'): """set the output file for all loggers. Alias to :func:`set_output_file`. Args: fout: the output file path. mode: the mode to open the file. """ set_output_file(fout, mode=mode)
[docs] def set_default_level(level, update_existing=True): """Set the default logging level for all loggers. Args: level: the level to set. update_existing: whether to update the existing loggers. """ global _g_default_level _g_default_level = level if update_existing: for i in _g_all_loggers: i.setLevel(level)
[docs] def set_logger_default_level(level, update_existing=True): """Set the default logging level for all loggers. Alias to :func:`set_default_level`. Args: level: the level to set. update_existing: whether to update the existing loggers. """ set_default_level(level, update_existing=update_existing)
[docs] class JacLogFormatter(logging.Formatter): log_fout = None date_full = '[%(asctime)s %(lineno)d@%(filename)s:%(name)s] ' date = '%(asctime)s ' msg = '%(message)s' max_lines = 256 def _color_dbg(self, msg): return '\x1b[36m{}\x1b[0m'.format(msg) def _color_warn(self, msg): return '\x1b[1;31m{}\x1b[0m'.format(msg) def _color_err(self, msg): return '\x1b[1;4;31m{}\x1b[0m'.format(msg) def _color_omitted(self, msg): return '\x1b[35m{}\x1b[0m'.format(msg) def _color_normal(self, msg): return msg def _color_date(self, msg): return '\x1b[32m{}\x1b[0m'.format(msg)
[docs] def format(self, record): if record.levelno == logging.DEBUG: mcl, mtxt = self._color_dbg, 'DBG' elif record.levelno == logging.WARNING: mcl, mtxt = self._color_warn, 'WRN' elif record.levelno == logging.ERROR: mcl, mtxt = self._color_err, 'ERR' else: mcl, mtxt = self._color_normal, '' if mtxt: mtxt += ' ' if self.log_fout: self.__set_fmt(self.date_full + mtxt + self.msg) formatted = super().format(record) nr_line = formatted.count('\n') + 1 if nr_line >= self.max_lines: head, body = formatted.split('\n', 1) formatted = '\n'.join([ head, 'BEGIN_LONG_LOG_{}_LINES{{'.format(nr_line - 1), body, '}}END_LONG_LOG_{}_LINES'.format(nr_line - 1) ]) self.log_fout.write(formatted) self.log_fout.write('\n') self.log_fout.flush() self.__set_fmt(self._color_date(self.date) + mcl(mtxt + self.msg)) formatted = super().format(record) nr_line = formatted.count('\n') + 1 if nr_line >= self.max_lines: lines = formatted.split('\n') remain = self.max_lines//2 removed = len(lines) - remain * 2 if removed > 0: mid_msg = self._color_omitted( '[{} log lines omitted (would be written to output file if set_output_file() has been called;\n' ' the threshold can be set at TALogFormatter.max_lines)].'.format(removed)) formatted = '\n'.join( lines[:remain] + [mid_msg] + lines[-remain:]) return formatted
if sys.version_info.major < 3: def __set_fmt(self, fmt): self._fmt = fmt else: def __set_fmt(self, fmt): self._style._fmt = fmt
[docs] def get_logger(name=None, formatter=JacLogFormatter): """Get logger with given name. Args: name: the name of the logger. formatter: the formatter to use. """ logger = logging.getLogger(name) if getattr(logger, '_init_done__', None): return logger logger._init_done__ = True logger.propagate = False logger.setLevel(_g_default_level) logger.warning_once = functools.partial(_warning_once, logger=logger) handler = logging.StreamHandler() handler.setFormatter(formatter(datefmt='%d %H:%M:%S')) handler.setLevel(0) del logger.handlers[:] logger.addHandler(handler) _g_all_loggers.append(logger) return logger
@functools.lru_cache(128) def _warning_once(message: str, logger): """Print a warning message only once. Args: logger: the logger to use. message: the message to print. """ return logger.warning(message) logger = get_logger('Jacinle') """The default logger of Jacinle."""