Last active
June 19, 2024 17:23
-
-
Save ColinDuquesnoy/8296508 to your computer and use it in GitHub Desktop.
HTML logger for python (inspired by the Horde3D logger)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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 = """<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title>%(title)s</title> | |
<style type="text/css"> | |
body, html { | |
background: #000000; | |
width: 1000px; | |
font-family: Arial; | |
font-size: 16px; | |
color: #C0C0C0; | |
} | |
h1 { | |
color : #FFFFFF; | |
border-bottom : 1px dotted #888888; | |
} | |
pre { | |
font-family : arial; | |
margin : 0; | |
} | |
.box { | |
border : 1px dotted #818286; | |
padding : 5px; | |
margin: 5px; | |
width: 950px; | |
background-color : #292929; | |
} | |
.err { | |
color: #EE1100; | |
font-weight: bold | |
} | |
.warn { | |
color: #FFCC00; | |
font-weight: bold | |
} | |
.info { | |
color: #C0C0C0; | |
} | |
.debug { | |
color: #CCA0A0; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>%(title)s</h1> | |
<h3>%(version)s</h3> | |
<div class="box"> | |
<table> | |
""" | |
_END_OF_DOC_FMT = """</table> | |
</div> | |
</body> | |
</html> | |
""" | |
_MSG_FMT = """ | |
<tr> | |
<td width="100">%(time)s</td> | |
<td class="%(class)s"><pre>%(msg)s</pre></td> | |
<tr> | |
""" | |
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") |
Thank you for your fast reply.
It worked for me!
I moved the HTMLlogger init to a separate function and created and returned
a logger object.
I was getting multiple files this way while looping.
…On Thu, 22 Aug 2019 at 5:23 PM, Colin Duquesnoy ***@***.***> wrote:
Sure, you just need to create a new HTMLLogger instance yourself (don't
use the setup method and the global logger)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<https://gist.github.com/8296508?email_source=notifications&email_token=AAJKM6LLVXO4H6O36A5FQBDQFZ44DA5CNFSM4IORVZZKYY3PNVWWK3TUL52HS4DFVNDWS43UINXW23LFNZ2KUY3PNVWWK3TUL5UWJTQAFXNYS#gistcomment-3005321>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAJKM6M4CFZCDXMW2AE5GD3QFZ44DANCNFSM4IORVZZA>
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sure, you just need to create a new HTMLLogger instance yourself (don't use the setup method and the global logger)