"""
=================
Logging Utilities
=================
This module contains utilities for configuring logging.
"""
import logging
import sys
from pathlib import Path
from loguru import logger
def _clear_default_configuration():
try:
logger.remove(0) # Clear default configuration
except ValueError:
pass
def _add_logging_sink(
sink,
verbosity: int,
long_format: bool,
colorize: bool,
serialize: bool,
) -> int:
"""Add a logging sink to the logger.
Parameters
----------
sink
The sink to add. Can be a file path, a file object, or a callable.
verbosity
The verbosity level. 0 is the default and will only log warnings and errors.
1 will log info messages. 2 will log debug messages.
long_format
Whether to use the long format for logging messages. The long format includes
the simulation name and component name. The short format only includes the
file name and line number.
colorize
Whether to colorize the log messages.
serialize
Whether to serialize log messages. This is useful when logging to
a file or a database.
"""
log_formatter = _LogFormatter(long_format)
logging_level = _get_log_level(verbosity)
return logger.add(
sink,
colorize=colorize,
level=logging_level,
format=log_formatter.format,
serialize=serialize,
)
class _LogFormatter:
time = "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green>"
level = "<level>{level: <8}</level>"
simulation = "<cyan>{extra[simulation]}</cyan> - <cyan>{name}</cyan>:<cyan>{line}</cyan>"
simulation_and_component = (
"<cyan>{extra[simulation]}</cyan>-<cyan>{extra[component]}</cyan>:<cyan>{line}</cyan>"
)
short_name_and_line = "<cyan>{name}</cyan>:<cyan>{line}</cyan>"
message = "<level>{message}</level>"
def __init__(self, long_format: bool = False):
self.long_format = long_format
def format(self, record):
fmt = self.time + " | "
if self.long_format:
fmt += self.level + " | "
if self.long_format and "simulation" in record["extra"]:
if "component" in record["extra"]:
fmt += self.simulation_and_component + " - "
else:
fmt += self.simulation + " - "
else:
fmt += self.short_name_and_line + " - "
fmt += self.message + "\n{exception}"
return fmt
def _get_log_level(verbosity: int):
if verbosity == 0:
return "WARNING"
elif verbosity == 1:
return "INFO"
elif verbosity >= 2:
return "DEBUG"
[docs]
def list_loggers():
"""Utility function for analyzing the logging environment."""
root_logger = logging.getLogger()
print("Root logger: ", root_logger)
for h in root_logger.handlers:
print(f" %s" % h)
print("Other loggers")
print("=============")
for name, logger_ in logging.Logger.manager.loggerDict.items():
print("+ [%-20s] %s " % (name, logger_))
if not isinstance(logger_, logging.PlaceHolder):
handlers = list(logger_.handlers)
if not handlers:
print(" No handlers")
for h in logger_.handlers:
print(" %s" % h)