logging_helper
– Logging extensions and helpers¶
Backports, extensions and customisations of the logging system
Use examples for QueueHandler
and QueueListener
can be found
here,
here
and here.
QueueHandler
and QueueListener
are copied from the cPython
3.5 branch commit 9aee273bf8b7
and
slightly modified (mostly documentation).
Examples¶
First the imports:
>>> import multiprocessing as mp
>>> import logging
>>> import sys
>>> import pyhetdex.tools.logging_helper as phlog
>>> import pyhetdex.tools.processes as p
and some utility functions
>>> # initialise the logger and the QueueHandler
>>> def init_logger(queue, name):
... qhandler = phlog.QueueHandler(queue)
... qhandler.setLevel(logging.INFO)
... logger = logging.getLogger(name)
... logger.setLevel(logging.INFO)
... logger.addHandler(qhandler)
... return logger
>>> # create the stdout handler
>>> def stdout_handler(fmt=None):
... shandler = logging.StreamHandler(stream=sys.stdout)
... if fmt is None:
... fmt = "[%(levelname)s] %(message)s"
... shandler.setFormatter(logging.Formatter(fmt=fmt))
... shandler.setLevel(logging.INFO)
... return shandler
>>> # function to execute in the worker pool
>>> def log_func(name, level, message):
... logger = logging.getLogger(name)
... logger.log(level, message)
Logging from the main process¶
This example show how to setup the
QueueHandler
and
QueueListener
to log from the main
process to standard output via a queue. Although this is a bit of overkill for
current the example, it could be useful if any of the handlers can blocks, like
if it needs an internet connection.
>>> # create the logger and add the QueueHandler
>>> logger_name = "single_proc"
>>> q_sp = mp.Queue()
>>> logger = init_logger(q_sp, logger_name)
>>> # start the QueueListener and log two messages
>>> with phlog.SetupQueueListener(q_sp, handlers=[stdout_handler()],
... use_process=False):
... logger.info("this is a demonstration")
... logger.error("this is an error")
[INFO] this is a demonstration
[ERROR] this is an error
>>> q_sp.close()
Logging from subprocesses¶
This way of logging becomes even more useful if you want to log to a common
place from multiple processes. First, it avoids logging multiple messages at the
same time, which can corrupt them; secondly it avoids that, when using e.g. the
logging.handlers.RotatingFileHandlers
, multiple handlers try to
move/rename/remove the same log file at the same time.
>>> logger_name = "multi_proc"
>>> q_mp = mp.Queue()
>>> # create a multiprocessing worker
>>> worker = p.get_worker(name="multip", multiprocessing=True,
... initializer=init_logger,
... initargs=(q_mp, logger_name))
>>> # start the QueueListener and run two jobs
>>> with phlog.SetupQueueListener(q_mp, handlers=[stdout_handler()],
... use_process=True):
... worker(log_func, logger_name, logging.INFO, "this is a demonstration")
... worker(log_func, logger_name, logging.ERROR, "this is an error")
... worker.get_results()
... worker.close()
[INFO] this is a demonstration
[ERROR] this is an error
>>> q_mp.close()
QueueHandler
– Put log records to a queue¶
-
class
pyhetdex.tools.logging_helper.
QueueHandler
(queue)[source]¶ Bases:
logging.Handler
This handler sends events to a queue. Typically, it would be used together with a multiprocessing Queue to centralise logging to file in one process (in a multi-process application), so as to avoid file write contention between processes.
This code is new in Python 3.2, but this class can be copy pasted into user code for use with earlier Python versions.
Parameters: - queue : queue-like instance
Initialise an instance, using the passed queue.
-
emit
(record)[source]¶ Emit a record.
Writes the LogRecord to the queue, preparing it for pickling first.
-
enqueue
(record)[source]¶ Enqueue a record.
The base implementation uses
put_nowait
. You may want to override this method if you want to use blocking, timeouts or custom queue implementations.
-
prepare
(record)[source]¶ Prepares a record for queuing. The object returned by this method is enqueued.
The base implementation formats the record to merge the message and arguments, and removes unpickleable items from the record in-place.
You might want to override this method if you want to convert the record to a dict or JSON string, or send a modified copy of the record while leaving the original intact.
QueueListener
– Log records from a queue¶
-
class
pyhetdex.tools.logging_helper.
QueueListener
(queue_, handlers=[], respect_handler_level=False)[source]¶ Bases:
pyhetdex.tools.queue.QueueListener
This class implements an internal threaded listener which watches for LogRecords being added to a queue, removes them and passes them to a list of handlers for processing.
Parameters: - queue_ : queue-like instance
- handlers : list of
logging.Handler
child instances - respect_handler_level : bool, optional
if
True
the handler’s level is respected
-
handle
(record)[source]¶ Handle a record.
This just loops through the handlers offering them the record to handle.
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 54¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
_sentinel
= None¶
SetupQueueListener
– Setup the QueueListener
¶
-
class
pyhetdex.tools.logging_helper.
SetupQueueListener
(queue_, handlers=[], respect_handler_level=True, use_process=True)[source]¶ Bases:
pyhetdex.tools.queue.SetupQueueListener
Start the
QueueListener
, in a separate process if required.Adapted from logging cookbook.
The
SetupQueueListener
instance can be used as a context manager for awith
statement. Upon exiting the statement, the process andQueueListener
are stopped. If an exception happens, it will be logged as critical before stopping: in order to avoid possible errors with missing formatter keywords, the handler formatters are temporarily substituted with “%(level)s %(message)s”.Parameters: - queue_ : queue-like object
queue which contains messages to log
- handlers : list of
logging.Handler
child instances - respect_handler_level : bool, optional
if
True
the handler’s level is respected- use_process : bool, optional
if
True
start the listener in a separate process
Attributes: - queue, handlers : as above
- stop_event :
multiprocessing.Event
instance event used to signal to stop the listener
- lp : :class multiprocessing.Process instance
process running the listener, if
use_process
isTrue
- listener :
QueueListener
instance