Source code for ufl.log

# -*- coding: utf-8 -*-
"""This module provides functions used by the UFL implementation to
output messages. These may be redirected by the user of UFL."""

# Copyright (C) 2005-2016 Anders Logg and Martin Sandve Alnaes
#
# This file is part of UFL (https://www.fenicsproject.org)
#
# SPDX-License-Identifier:    LGPL-3.0-or-later
#
# Modified by Johan Hake, 2009.
# Modified by Massimiliano Leoni, 2016

import sys
import types
import logging
from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL  # noqa: F401

log_functions = ["log", "debug", "info", "deprecate", "warning", "error",
                 "begin", "end",
                 "set_level", "push_level", "pop_level", "set_indent",
                 "add_indent",
                 "set_handler", "get_handler", "get_logger", "add_logfile",
                 "set_prefix",
                 "info_red", "info_green", "info_blue",
                 "warning_red", "warning_green", "warning_blue"]

__all__ = log_functions + ["Logger", "log_functions"] +\
    ["DEBUG", "INFO", "DEPRECATE", "WARNING", "ERROR", "CRITICAL"]


DEPRECATE = (INFO + WARNING) // 2


# This is used to override emit() in StreamHandler for printing
# without newline
def emit(self, record):
    message = self.format(record)
    format_string = "%s" if getattr(record, "continued", False) else "%s\n"
    self.stream.write(format_string % message)
    self.flush()


# Colors if the terminal supports it (disabled e.g. when piped to
# file)
if sys.stdout.isatty() and sys.stderr.isatty():
    RED = "\033[1;37;31m%s\033[0m"
    BLUE = "\033[1;37;34m%s\033[0m"
    GREEN = "\033[1;37;32m%s\033[0m"
else:
    RED = "%s"
    BLUE = "%s"
    GREEN = "%s"


# Logger class
[docs]class Logger: def __init__(self, name, exception_type=Exception): "Create logger instance." self._name = name self._exception_type = exception_type # Set up handler h = logging.StreamHandler(sys.stdout) h.setLevel(WARNING) # Override emit() in handler for indentation h.emit = types.MethodType(emit, h) self._handler = h # Set up logger self._log = logging.getLogger(name) assert len(self._log.handlers) == 0 self._log.addHandler(h) self._log.setLevel(DEBUG) self._logfiles = {} # Set initial indentation level self._indent_level = 0 # Setup stack with default logging level self._level_stack = [DEBUG] # Set prefix self._prefix = ""
[docs] def add_logfile(self, filename=None, mode="a", level=DEBUG): "Add a log file." if filename is None: filename = "%s.log" % self._name if filename in self._logfiles: self.warning("Adding logfile %s multiple times." % filename) return h = logging.FileHandler(filename, mode) h.emit = types.MethodType(emit, h) h.setLevel(level) self._log.addHandler(h) self._logfiles[filename] = h return h
[docs] def get_logfile_handler(self, filename): "Gets the handler to the file identified by the given file name." return self._logfiles[filename]
[docs] def log(self, level, *message): "Write a log message on given log level." text = self._format_raw(*message) if len(text) >= 3 and text[-3:] == "...": self._log.log(level, self._format(*message), extra={"continued": True}) else: self._log.log(level, self._format(*message))
[docs] def debug(self, *message): "Write debug message." self.log(DEBUG, *message)
[docs] def info(self, *message): "Write info message." self.log(INFO, *message)
[docs] def info_red(self, *message): "Write info message in red." self.log(INFO, RED % self._format_raw(*message))
[docs] def info_green(self, *message): "Write info message in green." self.log(INFO, GREEN % self._format_raw(*message))
[docs] def info_blue(self, *message): "Write info message in blue." self.log(INFO, BLUE % self._format_raw(*message))
[docs] def deprecate(self, *message): "Write deprecation message." self.log(DEPRECATE, RED % self._format_raw(*message))
[docs] def warning(self, *message): "Write warning message." self._log.warning(self._format(*message))
[docs] def warning_red(self, *message): "Write warning message in red." self._log.warning(RED % self._format(*message))
[docs] def warning_green(self, *message): "Write warning message in green." self._log.warning(GREEN % self._format(*message))
[docs] def warning_blue(self, *message): "Write warning message in blue." self._log.warning(BLUE % self._format(*message))
[docs] def error(self, *message): "Write error message and raise an exception." self._log.error(*message) raise self._exception_type(self._format_raw(*message))
[docs] def begin(self, *message): "Begin task: write message and increase indentation level." self.info(*message) self.info("-" * len(self._format_raw(*message))) self.add_indent()
[docs] def end(self): "End task: write a newline and decrease indentation level." self.info("") self.add_indent(-1)
[docs] def push_level(self, level): "Push a log level on the level stack." self._level_stack.append(level) self.set_level(level)
[docs] def pop_level(self): "Pop log level from the level stack, reverting to before the last push_level." self._level_stack.pop() level = self._level_stack[-1] self.set_level(level)
[docs] def set_level(self, level): "Set log level." self._level_stack[-1] = level self._handler.setLevel(level)
[docs] def set_indent(self, level): "Set indentation level." self._indent_level = level
[docs] def add_indent(self, increment=1): "Add to indentation level." self._indent_level += increment
[docs] def get_handler(self): "Get handler for logging." return self._handler
[docs] def set_handler(self, handler): """Replace handler for logging. To add additional handlers instead of replacing the existing one, use `log.get_logger().addHandler(myhandler)`. See the logging module for more details. """ self._log.removeHandler(self._handler) self._log.addHandler(handler) self._handler = handler handler.emit = types.MethodType(emit, self._handler)
[docs] def get_logger(self): "Return message logger." return self._log
[docs] def set_prefix(self, prefix): "Set prefix for log messages." self._prefix = prefix
def _format(self, *message): "Format message including indentation." indent = self._prefix + 2 * self._indent_level * " " return "\n".join([indent + line for line in (message[0] % message[1:]).split("\n")]) def _format_raw(self, *message): "Format message without indentation." return message[0] % message[1:]
# --- Set up global log functions ---
[docs]class UFLException(Exception): "Base class for UFL exceptions." pass
class UFLValueError(UFLException): "Value type error." pass ufl_logger = Logger("UFL", UFLException) for foo in log_functions: exec("%s = ufl_logger.%s" % (foo, foo)) set_level(DEPRECATE) # noqa