Source code for mdt.lib.log_handlers
"""Implements multiple handles that hook into the Python logging module.
These handlers can for example echo the log entry to the terminal, write it to a file or dispatch it to another class.
They are typically configured in the MDT configuration file.
"""
import codecs
from logging import StreamHandler
import os
import sys
__author__ = 'Robbert Harms'
__date__ = "2015-08-19"
__maintainer__ = "Robbert Harms"
__email__ = "robbert@xkls.nl"
[docs]class ModelOutputLogHandler(StreamHandler):
__instances__ = set()
def __init__(self, mode='a', encoding=None):
"""This logger logs information about a model optimization to the folder of the model that is being optimized.
It is by default (see the MDT configuration) already constructed and added to the logging module. To set a new
file, or to disable this logger set the file using the :attr:`output_file` property.
"""
super().__init__()
self.__class__.__instances__.add(self)
if codecs is None:
encoding = None
self._output_file = None
self.mode = mode
self.encoding = encoding
self.stream = None
@property
def output_file(self):
return self._output_file
@output_file.setter
def output_file(self, output_file):
self.close()
self._output_file = output_file
if self._output_file:
if not os.path.isdir(os.path.dirname(self._output_file)):
os.makedirs(os.path.dirname(self._output_file))
self._open()
[docs] def emit(self, record):
if self._output_file and self.stream:
super().emit(record)
[docs] def close(self):
if self._output_file:
self.acquire()
try:
if self.stream:
self.flush()
if hasattr(self.stream, "close"):
self.stream.close()
self.stream = None
super().close()
finally:
self.release()
def _open(self):
"""
Open the current base file with the (original) mode and encoding.
Return the resulting stream.
"""
if self._output_file:
if self.encoding is None:
self.stream = open(self._output_file, self.mode)
else:
self.stream = codecs.open(self._output_file, self.mode, self.encoding)
[docs]class StdOutHandler(StreamHandler):
def __init__(self, stream=None):
"""A redirect for stdout.
Emits all log entries to the stdout.
Args:
stream: the IO stream to which to emit the log entries. If not given we use sys.stdout.
"""
stream = stream or sys.stdout
super().__init__(stream=stream)
[docs] def emit(self, record):
if self.stream:
super().emit(record)
[docs]class LogDispatchHandler(StreamHandler):
_listeners = []
def __init__(self, *args, **kwargs):
"""This class is able to dispatch messages to all the attached log listeners.
You can add listeners by adding them to the list of listeners. This list is a class variable and as such is
available to all instances and subclasses.
The listeners should be of instance LogListenerInterface.
This enables for example the GUI to hook a log listener indirectly into the logging module.
In general only one copy of this class should be used.
"""
super().__init__(*args, **kwargs)
[docs] def emit(self, record):
for listener in self._listeners:
listener.emit(record, self.format(record))
[docs] @staticmethod
def add_listener(listener):
"""Add a listener to the dispatch handler.
Args:
listener (LogListenerInterface): listener that implements the log listener interface.
Returns:
int: the listener id number. You can use this to remove the listener again.
"""
listener_id = len(LogDispatchHandler._listeners)
LogDispatchHandler._listeners.append(listener)
return listener_id
[docs] @staticmethod
def remove_listener(listener_id):
"""Remove a listener from the log dispatcher.
Args:
listener_id (int): the id of the listener to remove
"""
del LogDispatchHandler._listeners[listener_id]
[docs]class LogListenerInterface:
"""Interface for listeners to work in conjunction with :class:`LogDispatchHandler`"""
[docs] def emit(self, record, formatted_message):
pass