2016-11-12 04:22:39 +03:00
|
|
|
# Code to implement asynchronous logging from a background thread
|
|
|
|
#
|
2019-12-17 17:51:45 +03:00
|
|
|
# Copyright (C) 2016-2019 Kevin O'Connor <kevin@koconnor.net>
|
2016-11-12 04:22:39 +03:00
|
|
|
#
|
|
|
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
2017-05-01 20:44:06 +03:00
|
|
|
import logging, logging.handlers, threading, Queue, time
|
2016-11-12 04:22:39 +03:00
|
|
|
|
|
|
|
# Class to forward all messages through a queue to a background thread
|
|
|
|
class QueueHandler(logging.Handler):
|
|
|
|
def __init__(self, queue):
|
|
|
|
logging.Handler.__init__(self)
|
|
|
|
self.queue = queue
|
|
|
|
def emit(self, record):
|
|
|
|
try:
|
|
|
|
self.format(record)
|
|
|
|
record.msg = record.message
|
|
|
|
record.args = None
|
|
|
|
record.exc_info = None
|
|
|
|
self.queue.put_nowait(record)
|
|
|
|
except Exception:
|
|
|
|
self.handleError(record)
|
|
|
|
|
|
|
|
# Class to poll a queue in a background thread and log each message
|
2017-05-01 20:44:06 +03:00
|
|
|
class QueueListener(logging.handlers.TimedRotatingFileHandler):
|
|
|
|
def __init__(self, filename):
|
|
|
|
logging.handlers.TimedRotatingFileHandler.__init__(
|
|
|
|
self, filename, when='midnight', backupCount=5)
|
|
|
|
self.bg_queue = Queue.Queue()
|
|
|
|
self.bg_thread = threading.Thread(target=self._bg_thread)
|
|
|
|
self.bg_thread.start()
|
|
|
|
self.rollover_info = {}
|
2016-11-12 04:22:39 +03:00
|
|
|
def _bg_thread(self):
|
|
|
|
while 1:
|
2017-05-01 20:44:06 +03:00
|
|
|
record = self.bg_queue.get(True)
|
2016-11-12 04:22:39 +03:00
|
|
|
if record is None:
|
|
|
|
break
|
2017-05-01 20:44:06 +03:00
|
|
|
self.handle(record)
|
2016-11-12 04:22:39 +03:00
|
|
|
def stop(self):
|
2017-05-01 20:44:06 +03:00
|
|
|
self.bg_queue.put_nowait(None)
|
|
|
|
self.bg_thread.join()
|
|
|
|
def set_rollover_info(self, name, info):
|
|
|
|
self.rollover_info[name] = info
|
2018-04-03 19:13:06 +03:00
|
|
|
def clear_rollover_info(self):
|
|
|
|
self.rollover_info.clear()
|
2017-05-01 20:44:06 +03:00
|
|
|
def doRollover(self):
|
|
|
|
logging.handlers.TimedRotatingFileHandler.doRollover(self)
|
|
|
|
lines = [self.rollover_info[name]
|
2018-04-03 19:13:06 +03:00
|
|
|
for name in sorted(self.rollover_info)]
|
2017-05-01 20:44:06 +03:00
|
|
|
lines.append(
|
|
|
|
"=============== Log rollover at %s ===============" % (
|
|
|
|
time.asctime(),))
|
|
|
|
self.emit(logging.makeLogRecord(
|
|
|
|
{'msg': "\n".join(lines), 'level': logging.INFO}))
|
2016-11-12 04:22:39 +03:00
|
|
|
|
2019-12-17 17:51:45 +03:00
|
|
|
MainQueueHandler = None
|
|
|
|
|
2016-11-12 04:22:39 +03:00
|
|
|
def setup_bg_logging(filename, debuglevel):
|
2019-12-17 17:51:45 +03:00
|
|
|
global MainQueueHandler
|
2017-05-01 20:44:06 +03:00
|
|
|
ql = QueueListener(filename)
|
2019-12-17 17:51:45 +03:00
|
|
|
MainQueueHandler = QueueHandler(ql.bg_queue)
|
2016-11-12 04:22:39 +03:00
|
|
|
root = logging.getLogger()
|
2019-12-17 17:51:45 +03:00
|
|
|
root.addHandler(MainQueueHandler)
|
2016-11-12 04:22:39 +03:00
|
|
|
root.setLevel(debuglevel)
|
|
|
|
return ql
|
2019-12-17 17:51:45 +03:00
|
|
|
|
|
|
|
def clear_bg_logging():
|
|
|
|
global MainQueueHandler
|
|
|
|
if MainQueueHandler is not None:
|
|
|
|
root = logging.getLogger()
|
|
|
|
root.removeHandler(MainQueueHandler)
|
|
|
|
root.setLevel(logging.WARNING)
|
|
|
|
MainQueueHandler = None
|