# -*- 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