Source code for aeneas.logger

#!/usr/bin/env python
# coding=utf-8

# aeneas is a Python/C library and a set of tools
# to automagically synchronize audio and text (aka forced alignment)
#
# Copyright (C) 2012-2013, Alberto Pettarin (www.albertopettarin.it)
# Copyright (C) 2013-2015, ReadBeyond Srl   (www.readbeyond.it)
# Copyright (C) 2015-2017, Alberto Pettarin (www.albertopettarin.it)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
This module contains the following classes:

* :class:`~aeneas.logger.Loggable`, a base class supporting logging and runtime configuration;
* :class:`~aeneas.logger.Logger`, a logger class for debugging and performance profiling.

"""

from __future__ import absolute_import
from __future__ import print_function
import datetime
import io

from aeneas.runtimeconfiguration import RuntimeConfiguration
import aeneas.globalfunctions as gf


[docs]class Logger(object): """ A logger class for debugging and performance profiling. :param bool tee: if ``True``, tee (i.e., log and print to stdout) :param int indentation: the initial indentation of the log :param bool tee_show_datetime: if ``True``, print date and time when teeing """ DEBUG = "DEBU" """ ``DEBUG`` severity """ INFO = "INFO" """ ``INFO`` severity """ WARNING = "WARN" """ ``WARNING`` severity """ CRITICAL = "CRIT" """ ``CRITICAL`` severity """ ERROR = "ERRO" """ ``ERROR`` message """ SUCCESS = "SUCC" """ ``SUCCESS`` message """ def __init__(self, tee=False, indentation=0, tee_show_datetime=True): self.entries = [] self.tee = tee self.indentation = indentation self.tee_show_datetime = tee_show_datetime def __len__(self): return len(self.entries) def __unicode__(self): return self.pretty_print() def __str__(self): return gf.safe_str(self.__unicode__()) def __repr__(self): return u"Logger(tee=%s, indentation=%d, tee_show_datetime=%s)" % ( self.tee, self.indentation, self.tee_show_datetime ) @property def tee(self): """ If ``True``, tee (i.e., log and print to stdout). :rtype: bool """ return self.__tee @tee.setter def tee(self, tee): self.__tee = tee @property def tee_show_datetime(self): """ If ``True``, print date and time when teeing. :rtype: bool """ return self.__tee_show_datetime @tee_show_datetime.setter def tee_show_datetime(self, tee_show_datetime): self.__tee_show_datetime = tee_show_datetime @property def indentation(self): """ The current indentation of the log. Useful to visually distinguish log levels. :rtype: int """ return self.__indentation @indentation.setter def indentation(self, indentation): self.__indentation = indentation
[docs] def pretty_print(self, as_list=False, show_datetime=True): """ Return a Unicode string pretty print of the log entries. :param bool as_list: if ``True``, return a list of Unicode strings, one for each entry, instead of a Unicode string :param bool show_datetime: if ``True``, show the date and time of the entries :rtype: string or list of strings """ ppl = [entry.pretty_print(show_datetime) for entry in self.entries] if as_list: return ppl return u"\n".join(ppl)
[docs] def log(self, message, severity=INFO, tag=u""): """ Add a given message to the log, and return its time. :param string message: the message to be added :param severity: the severity of the message :type severity: :class:`~aeneas.logger.Logger` :param string tag: the tag associated with the message; usually, the name of the class generating the entry :rtype: datetime """ entry = _LogEntry( severity=severity, time=datetime.datetime.now(), tag=tag, indentation=self.indentation, message=self._sanitize(message) ) self.entries.append(entry) if self.tee: gf.safe_print(entry.pretty_print(show_datetime=self.tee_show_datetime)) return entry.time
[docs] def clear(self): """ Clear the contents of the log. """ self.entries = []
[docs] def write(self, path): """ Output the log to file. :param string path: the path of the log file to be written """ with io.open(path, "w", encoding="utf-8") as log_file: log_file.write(self.pretty_print())
@classmethod def _sanitize(cls, message): """ Sanitize the given message, dealing with multiple arguments and/or string formatting. :param message: the log message to be sanitized :type message: string or list of strings :rtype: string """ if isinstance(message, list): if len(message) == 0: sanitized = u"Empty log message" elif len(message) == 1: sanitized = message[0] else: sanitized = message[0] % tuple(message[1:]) else: sanitized = message if not gf.is_unicode(sanitized): raise TypeError("The given log message is not a Unicode string") return sanitized
class _LogEntry(object): """ A structure for a log entry. """ def __init__(self, message, severity, tag, indentation, time): self.message = message self.severity = severity self.tag = tag self.indentation = indentation self.time = time def pretty_print(self, show_datetime=True): """ Returns a Unicode string containing the pretty printing of a given log entry. :param bool show_datetime: if ``True``, print the date and time of the entry :rtype: string """ if show_datetime: return u"[%s] %s %s%s: %s" % ( self.severity, gf.object_to_unicode(self.time), u" " * self.indentation, self.tag, self.message ) return u"[%s] %s%s: %s" % ( self.severity, u" " * self.indentation, self.tag, self.message ) @property def message(self): """ The message of this log entry. :rtype: string """ return self.__message @message.setter def message(self, message): self.__message = message @property def severity(self): """ The severity of this log entry. :rtype: :class:`~aeneas.logger.Logger` """ return self.__severity @severity.setter def severity(self, severity): self.__severity = severity @property def tag(self): """ The tag of this log entry. :rtype: string """ return self.__tag @tag.setter def tag(self, tag): self.__tag = tag @property def indentation(self): """ The indentation of this log entry. :rtype: string """ return self.__indentation @indentation.setter def indentation(self, indentation): self.__indentation = indentation @property def time(self): """ The date and time of this log entry. :rtype: datetime.time """ return self.__time @time.setter def time(self, time): self.__time = time
[docs]class Loggable(object): """ A base class supporting logging and runtime configuration. :param logger: the logger object :type logger: :class:`~aeneas.logger.Logger` :param rconf: the runtime configuration object :type rconf: :class:`~aeneas.runtimeconfiguration.RuntimeConfiguration` """ TAG = u"Loggable" def __init__(self, logger=None, rconf=None): self.logger = logger if logger is not None else Logger() self.rconf = rconf if rconf is not None else RuntimeConfiguration() def _log(self, message, severity=Logger.DEBUG): """ Log generic message :param string message: the message to log :param string severity: the message severity :rtype: datetime """ return self.logger.log(message, severity, self.TAG)
[docs] def log_exc(self, message, exc=None, critical=True, raise_type=None): """ Log exception, and possibly raise exception. :param string message: the message to log :param Exception exc: the original exception :param bool critical: if ``True``, log as :data:`aeneas.logger.Logger.CRITICAL`; otherwise as :data:`aeneas.logger.Logger.WARNING` :param Exception raise_type: if not ``None``, raise this Exception type """ log_function = self.log_crit if critical else self.log_warn log_function(message) if exc is not None: log_function([u"%s", exc]) if raise_type is not None: raise_message = message if exc is not None: raise_message = u"%s : %s" % (message, exc) raise raise_type(raise_message)
[docs] def log(self, message): """ Log DEBUG message, and return its time. :param string message: the message to log :rtype: datetime """ return self._log(message)
[docs] def log_info(self, message): """ Log INFO message, and return its time. :param string message: the message to log :rtype: datetime """ return self._log(message, Logger.INFO)
[docs] def log_warn(self, message): """ Log WARNING message, and return its time. :param string message: the message to log :rtype: datetime """ return self._log(message, Logger.WARNING)
[docs] def log_crit(self, message): """ Log CRITICAL message, and return its time. :param string message: the message to log :rtype: datetime """ return self._log(message, Logger.CRITICAL)