Making a logging handler that produces context.
Peter Otten
__peter__ at web.de
Mon Jan 14 07:38:12 EST 2013
Antoon Pardon wrote:
> I have some in house code for which I am considering replacing the
> logging code with something that uses the logging module.
> However there is one thing the in-house log code does, that seems
> difficult to do with the logging module, provide some context. The
> in-house handlers give the possibilty to specify the number of lines of
> context the hander can provide.
> So the following code:
> Logger(fl = stderr, level = warning, context = 2)
>
> log(INFO, "line 1")
> log(INFO, "line 2")
> log(INFO, "line 3")
> log(INFO, "line 4")
> log(WARNING, "line 5")
>
> Will sent something like the following lines to stderr:
>
> INFO: line 3
> INFO: line 4
> WARNING: line 5
>
> I tried the code below, but that produced the same
> as the ordinary StreamHandler.
>
> class ContextStreamHandler (StreamHandler):
>
> def __init__(self, stream=None, context = 5):
> self.recqueue = deque([], context)
> StreamHandler.__init__(self, stream)
> #__init__
>
> def handle(self, record):
> print("CONTEXT HANDLER")
> rv = self.filter(record)
> if rv:
> self.acquire()
> try:
> for rec in self.recqueue:
> self.emit(rec)
> self.recqueue.clear()
> self.emit(record)
> finally:
> self.release
> else:
> self.recqueue.append(record)
> return rv
> #handle
> #ContextStreamHandler
It turns out the logic of the above is correct. The problem is that the
handler has to see the INFO-level records while the filter() method has to
reject them. The following configuration seems to achieve that:
import logging
from collections import deque
class ContextStreamHandler(logging.StreamHandler):
def __init__(self, stream=None, context=5):
self.record_queue = deque([], context + 1)
logging.StreamHandler.__init__(self, stream)
def handle(self, record):
rv = self.filter(record)
self.record_queue.append(record)
if rv:
self.acquire()
try:
for record in self.record_queue:
self.emit(record)
self.record_queue.clear()
finally:
self.release()
return rv
class LevelFilter(logging.Filter):
def __init__(self, level, name=""):
logging.Filter.__init__(self, name)
self._filter_level = level
def filter(self, record):
return record.levelno >= self._filter_level
if __name__ == "__main__":
root = logging.getLogger()
root.setLevel(logging.INFO)
handler = ContextStreamHandler(context=2)
handler.addFilter(LevelFilter(logging.WARN))
root.addHandler(handler)
for i in range(20):
if i % 5:
root.info("message #%d" % i)
else:
root.warn("MESSAGE #%d" % i)
More information about the Python-list
mailing list