import logging
import logging.handlers as handlers
import sys
from contextlib import contextmanager
from typing import Dict, Optional
import colorama
from colorama import Back, Fore, Style
from popsynth.utils.configuration import popsynth_config
from popsynth.utils.package_data import get_path_of_log_dir, get_path_of_log_file
colorama.deinit()
colorama.init(strip=False)
# set up the console logging
[docs]class MyFilter(object):
[docs] def __init__(self, level):
self.__level = level
[docs] def filter(self, logRecord):
return logRecord.levelno != self.__level
# now create the developer handler that rotates every day and keeps
# 10 days worth of backup
popsynth_dev_log_handler = handlers.TimedRotatingFileHandler(
get_path_of_log_file("dev.log"), when="D", interval=1, backupCount=10)
# lots of info written out
_dev_formatter = logging.Formatter(
"%(asctime)s | %(name)s | %(levelname)s| %(funcName)s | %(lineno)d | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
popsynth_dev_log_handler.setFormatter(_dev_formatter)
popsynth_dev_log_handler.setLevel(logging.DEBUG)
# now set up the usr log which will save the info
popsynth_usr_log_handler = handlers.TimedRotatingFileHandler(
get_path_of_log_file("usr.log"), when="D", interval=1, backupCount=10)
popsynth_usr_log_handler.setLevel(popsynth_config["logging"]["file"]["level"])
# lots of info written out
_usr_formatter = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S")
popsynth_usr_log_handler.setFormatter(_usr_formatter)
# now set up the console logger
_console_formatter = ColoredFormatter(
"{color} {levelname:8} {reset}| {color} {message} {reset}",
style="{",
datefmt="%Y-%m-%d %H:%M:%S",
colors={
"DEBUG": Fore.CYAN,
"INFO": Fore.GREEN + Style.BRIGHT,
"WARNING": Fore.YELLOW + Style.DIM,
"ERROR": Fore.RED + Style.BRIGHT,
"CRITICAL": Fore.RED + Back.WHITE + Style.BRIGHT,
},
)
popsynth_console_log_handler = logging.StreamHandler(sys.stdout)
popsynth_console_log_handler.setFormatter(_console_formatter)
popsynth_console_log_handler.setLevel(
popsynth_config["logging"]["console"]["level"])
warning_filter = MyFilter(logging.WARNING)
[docs]class LoggingState(object):
[docs] def __init__(
self,
popsynth_usr_log_handler,
popsynth_console_log_handler,
):
"""
A container to store the state of the logs.
"""
# attach the log handlers
self.popsynth_usr_log_handler = popsynth_usr_log_handler
self.popsynth_console_log_handler = popsynth_console_log_handler
# store their current states
self.popsynth_usr_log_handler_state = popsynth_usr_log_handler.level
self.popsynth_console_log_handler_state = popsynth_console_log_handler.level
def _store_state(self):
self.popsynth_usr_log_handler_state = popsynth_usr_log_handler.level
self.popsynth_console_log_handler_state = popsynth_console_log_handler.level
[docs] def restore_last_state(self):
self.popsynth_usr_log_handler.setLevel(
self.popsynth_usr_log_handler_state)
self.popsynth_console_log_handler.setLevel(
self.popsynth_console_log_handler_state)
[docs] def silence_logs(self):
# store the state
self._store_state()
# silence the logs
self.popsynth_usr_log_handler.setLevel(logging.CRITICAL)
self.popsynth_console_log_handler.setLevel(logging.CRITICAL)
[docs] def loud_logs(self):
# store the state
self._store_state()
# silence the logs
self.popsynth_usr_log_handler.setLevel(logging.INFO)
self.popsynth_console_log_handler.setLevel(logging.INFO)
[docs] def debug_logs(self):
# store the state
self._store_state()
# silence the logs
self.popsynth_console_log_handler.setLevel(logging.DEBUG)
_log_state = LoggingState(
popsynth_usr_log_handler,
popsynth_console_log_handler,
)
[docs]def silence_warnings():
"""
Supress warning messages in console and file usr logs.
"""
popsynth_usr_log_handler.addFilter(warning_filter)
popsynth_console_log_handler.addFilter(warning_filter)
[docs]def activate_warnings():
"""
Supress warning messages in console and file usr logs.
"""
popsynth_usr_log_handler.removeFilter(warning_filter)
popsynth_console_log_handler.removeFilter(warning_filter)
[docs]def update_logging_level(level):
popsynth_console_log_handler.setLevel(level)
[docs]def silence_logs():
"""
Turn off all logging.
"""
# handle dev logs independently
popsynth_dev_log_handler.setLevel(logging.CRITICAL)
_log_state.silence_logs()
[docs]def show_progress_bars():
popsynth_config.show_progress = True
[docs]def silence_progress_bars():
popsynth_config.show_progress = False
[docs]def quiet_mode():
"""
Turn off all logging and progress bars.
"""
silence_progress_bars()
# save state and silence
silence_logs()
[docs]def loud_mode():
"""
Turn on all progress bars and logging.
"""
show_progress_bars()
# save state and make loud
_log_state.loud_logs()
[docs]def activate_logs():
"""
Re-activate silenced logs.
"""
# handle dev logs independently
popsynth_dev_log_handler.setLevel(logging.DEBUG)
_log_state.restore_last_state()
[docs]def debug_mode():
"""
Activate debug in the console.
"""
# store state and switch console to debug
_log_state.debug_logs()
[docs]@contextmanager
def silence_console_log():
current_console_logging_level = popsynth_console_log_handler.level
current_usr_logging_level = popsynth_usr_log_handler.level
popsynth_console_log_handler.setLevel(logging.ERROR)
popsynth_usr_log_handler.setLevel(logging.ERROR)
try:
yield
finally:
popsynth_console_log_handler.setLevel(current_console_logging_level)
popsynth_usr_log_handler.setLevel(current_usr_logging_level)
[docs]def setup_logger(name):
"""
Set up a new logger.
:param name: Name of the logger
"""
# A logger with name name will be created
# and then add it to the print stream
log = logging.getLogger(name)
# this must be set to allow debug messages through
log.setLevel(logging.DEBUG)
# add the handlers
if popsynth_config["logging"]["debug"]:
log.addHandler(popsynth_dev_log_handler)
if popsynth_config["logging"]["console"]["on"]:
log.addHandler(popsynth_console_log_handler)
if popsynth_config["logging"]["file"]["on"]:
log.addHandler(popsynth_usr_log_handler)
# we do not want to duplicate teh messages in the parents
log.propagate = False
return log