""" HTML logger inspired by the Horde3D logger. Usage: - call setup and specify the filename, title, version and level - call dbg, info, warn or err to log messages. """ import logging import time #: HTML header (starts the document _START_OF_DOC_FMT = """ %(title)s

%(title)s

%(version)s

""" _END_OF_DOC_FMT = """
""" _MSG_FMT = """ %(time)s
%(msg)s
""" class HTMLFileHandler(logging.FileHandler): """ File handler specialised to write the start of doc as html and to close it properly. """ def __init__(self, title, version, *args): super().__init__(*args) assert self.stream is not None # Write header self.stream.write(_START_OF_DOC_FMT % {"title": title, "version": version}) def close(self): # finish document self.stream.write(_END_OF_DOC_FMT) super().close() class HTMLFormatter(logging.Formatter): """ Formats each record in html """ CSS_CLASSES = {'WARNING': 'warn', 'INFO': 'info', 'DEBUG': 'debug', 'CRITICAL': 'err', 'ERROR': 'err'} def __init__(self): super().__init__() self._start_time = time.time() def format(self, record): try: class_name = self.CSS_CLASSES[record.levelname] except KeyError: class_name = "info" t = time.time() - self._start_time # handle '<' and '>' (typically when logging %r) msg = record.msg msg = msg.replace("<", "<") msg = msg.replace(">", ">") return _MSG_FMT % {"class": class_name, "time": "%.4f" % t, "msg": msg} class HTMLLogger(logging.Logger): """ Log records to html using a custom HTML formatter and a specialised file stream handler. """ def __init__(self, name="html_logger", level=logging.DEBUG, filename="log.html", mode='w', title="HTML Logger", version="1.0.0"): super().__init__(name, level) f = HTMLFormatter() h = HTMLFileHandler(title, version, filename, mode) h.setFormatter(f) self.addHandler(h) #: Global logger instance _logger = None def setup(title, version, filename="log.html", mode='w', level=logging.DEBUG): """ Setup the logger :param title: Title of the html document :param version: Framework/lib/app version :param filename: output filename. Default is "log.html" :param mode: File open mode. Default is 'w' :param level: handler output level. Default is DEBUG """ global _logger if _logger is None: _logger = HTMLLogger(filename=filename, mode=mode, title=title, version=version, level=level) def dbg(msg): """ Logs a debug message """ global _logger _logger.debug(msg) def info(msg): """ Logs an info message """ global _logger _logger.info(msg) def warn(msg): """ Logs a warning message """ global _logger _logger.warning(msg) def err(msg): """ Logs an error message """ global _logger _logger.error(msg) # Example of usage if __name__ == "__main__": setup("Example", "1.0") dbg("A debug message") info("An information message") warn("A warning message") time.sleep(1) err("An error message")