"""Logging utilities."""
import logging
import logging.config
from contextlib import contextmanager
from copy import deepcopy
from time import process_time
__all__ = [
"Formatter",
"make_formatter",
"setup",
"silence_log",
]
[docs]@contextmanager
def silence_log():
"""Context manager to temporarily silence log output.
Examples
--------
>>> with silence_log():
>>> log.warning("This message is not recorded.")
"""
# Restore the log level at the end of the context
with preserve_log_level():
# Set the level to a very high value
logging.getLogger(__name__.split(".")[0]).setLevel(100)
yield
@contextmanager
def preserve_log_level():
"""Context manager to preserve the level of the ``message_ix_models`` logger."""
# Get the top-level logger for the package containing this file
main_log = logging.getLogger(__name__.split(".")[0])
try:
# Store the current level
level = main_log.getEffectiveLevel()
yield
finally:
# Restore the level
main_log.setLevel(level)
_TIMES = []
def mark_time(quiet=False):
"""Record and log (if `quiet` is :obj:`True`) a time mark."""
_TIMES.append(process_time())
if not quiet and len(_TIMES) > 1:
logging.getLogger(__name__).info(
f" +{_TIMES[-1] - _TIMES[-2]:.1f} = {_TIMES[-1]:.1f} seconds"
)
CONFIG = dict(
version=1,
disable_existing_loggers=False,
formatters=dict(simple={"()": "message_ix_models.util._logging.make_formatter"}),
handlers=dict(
console={
"class": "logging.StreamHandler",
"level": "NOTSET",
"formatter": "simple",
"stream": "ext://sys.stdout",
},
# commented: needs code in setup() to choose an appropriate file path
# file_handler={
# "class": "logging.handlers.RotatingFileHandler",
# "level": "DEBUG",
# "formatter": "simple",
# "backupCount": "100",
# "delay": True,
# },
),
loggers=dict(
message_ix_models=dict(
level="NOTSET",
# propagate=False,
# handlers=[],
),
message_data=dict(
level="NOTSET",
# propagate=False,
# handlers=[],
),
),
root=dict(
handlers=[],
),
)
[docs]def setup(
level="NOTSET",
console=True,
# file=False,
):
"""Initialize logging.
Parameters
----------
level : str, optional
Log level for :mod:`message_ix_models` and :mod:`message_data`.
console : bool, optional
If :obj:`True`, print all messages to console using a :class:`Formatter`.
"""
# Copy to avoid modifying with the operations below
config = deepcopy(CONFIG)
config["root"].setdefault("level", level)
if console:
config["root"]["handlers"].append("console")
# if file:
# config["loggers"]["message_data"]["handlers"].append("file")
# Apply the configuration
logging.config.dictConfig(config)