mirror of
https://github.com/Casvt/MIND.git
synced 2026-02-19 11:54:46 -05:00
196 lines
5.1 KiB
Python
196 lines
5.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import logging
|
|
import logging.config
|
|
from io import StringIO
|
|
from os.path import exists, isdir, join
|
|
from typing import Any, Union
|
|
|
|
from backend.base.definitions import Constants
|
|
|
|
|
|
class UpToInfoFilter(logging.Filter):
|
|
def filter(self, record: logging.LogRecord) -> bool:
|
|
return record.levelno <= logging.INFO
|
|
|
|
|
|
class ErrorColorFormatter(logging.Formatter):
|
|
def format(self, record: logging.LogRecord) -> Any:
|
|
result = super().format(record)
|
|
return f'\033[1;31:40m{result}\033[0m'
|
|
|
|
|
|
LOGGER = logging.getLogger(Constants.LOGGER_NAME)
|
|
LOGGING_CONFIG = {
|
|
"version": 1,
|
|
"disable_existing_loggers": False,
|
|
"formatters": {
|
|
"simple": {
|
|
"format": "[%(asctime)s][%(levelname)s] %(message)s",
|
|
"datefmt": "%H:%M:%S"
|
|
},
|
|
"simple_red": {
|
|
"()": ErrorColorFormatter,
|
|
"format": "[%(asctime)s][%(levelname)s] %(message)s",
|
|
"datefmt": "%H:%M:%S"
|
|
},
|
|
"detailed": {
|
|
"format": "%(asctime)s | %(threadName)s | %(filename)sL%(lineno)s | %(levelname)s | %(message)s",
|
|
"datefmt": "%Y-%m-%dT%H:%M:%S%z",
|
|
}
|
|
},
|
|
"filters": {
|
|
"up_to_info": {
|
|
"()": UpToInfoFilter
|
|
},
|
|
},
|
|
"handlers": {
|
|
"console_error": {
|
|
"class": "logging.StreamHandler",
|
|
"level": "WARNING",
|
|
"formatter": "simple_red",
|
|
"stream": "ext://sys.stderr"
|
|
},
|
|
"console": {
|
|
"class": "logging.StreamHandler",
|
|
"level": "DEBUG",
|
|
"formatter": "simple",
|
|
"filters": ["up_to_info"],
|
|
"stream": "ext://sys.stdout"
|
|
},
|
|
"file": {
|
|
"class": "logging.handlers.RotatingFileHandler",
|
|
"level": "DEBUG",
|
|
"formatter": "detailed",
|
|
"filename": "",
|
|
"maxBytes": 1_000_000,
|
|
"backupCount": 1
|
|
}
|
|
},
|
|
"loggers": {
|
|
Constants.LOGGER_NAME: {}
|
|
},
|
|
"root": {
|
|
"level": "INFO",
|
|
"handlers": [
|
|
"console",
|
|
"console_error",
|
|
"file"
|
|
]
|
|
}
|
|
}
|
|
|
|
|
|
def setup_logging(log_folder: Union[str, None]) -> None:
|
|
"""Setup the basic config of the logging module.
|
|
|
|
Args:
|
|
log_folder (Union[str, None]): The folder to put the log file in.
|
|
If `None`, the log file will be in the same folder as the
|
|
application folder.
|
|
|
|
Raises:
|
|
ValueError: The given log folder is not a folder.
|
|
"""
|
|
from backend.base.helpers import create_folder, folder_path
|
|
|
|
if log_folder:
|
|
if exists(log_folder) and not isdir(log_folder):
|
|
raise ValueError("Logging folder is not a folder")
|
|
|
|
create_folder(log_folder)
|
|
|
|
if log_folder is None:
|
|
LOGGING_CONFIG["handlers"]["file"]["filename"] = folder_path(
|
|
Constants.LOGGER_FILENAME
|
|
)
|
|
else:
|
|
LOGGING_CONFIG["handlers"]["file"]["filename"] = join(
|
|
log_folder,
|
|
Constants.LOGGER_FILENAME
|
|
)
|
|
|
|
logging.config.dictConfig(LOGGING_CONFIG)
|
|
|
|
# Log uncaught exceptions using the logger instead of printing the stderr
|
|
# Logger goes to stderr anyway, so still visible in console but also logs
|
|
# to file, so that downloaded log file also contains any errors.
|
|
import sys
|
|
import threading
|
|
from traceback import format_exception
|
|
|
|
def log_uncaught_exceptions(e_type, value, tb):
|
|
LOGGER.error(
|
|
"UNCAUGHT EXCEPTION:\n" +
|
|
''.join(format_exception(e_type, value, tb))
|
|
)
|
|
return
|
|
|
|
def log_uncaught_threading_exceptions(args):
|
|
LOGGER.exception(
|
|
f"UNCAUGHT EXCEPTION IN THREAD: {args.exc_value}"
|
|
)
|
|
return
|
|
|
|
sys.excepthook = log_uncaught_exceptions
|
|
threading.excepthook = log_uncaught_threading_exceptions
|
|
|
|
return
|
|
|
|
|
|
def get_log_filepath() -> str:
|
|
"""Get the filepath to the logging file.
|
|
|
|
Returns:
|
|
str: The filepath.
|
|
"""
|
|
return LOGGING_CONFIG["handlers"]["file"]["filename"]
|
|
|
|
|
|
def get_log_file_contents() -> StringIO:
|
|
"""Get all the logs from the log file(s).
|
|
|
|
Raises:
|
|
LogFileNotFound: The log file does not exist.
|
|
|
|
Returns:
|
|
StringIO: The contents of the log file(s).
|
|
"""
|
|
from backend.base.custom_exceptions import LogFileNotFound
|
|
|
|
file = get_log_filepath()
|
|
if not exists(file):
|
|
raise LogFileNotFound(file)
|
|
|
|
sio = StringIO()
|
|
for ext in ('.1', ''):
|
|
lf = file + ext
|
|
if not exists(lf):
|
|
continue
|
|
with open(lf, 'r') as f:
|
|
sio.writelines(f)
|
|
|
|
return sio
|
|
|
|
|
|
def set_log_level(
|
|
level: Union[int, str],
|
|
) -> None:
|
|
"""Change the logging level.
|
|
|
|
Args:
|
|
level (Union[int, str]): The level to set the logging to.
|
|
Should be a logging level, like `logging.INFO` or `"DEBUG"`.
|
|
"""
|
|
if isinstance(level, str):
|
|
level = logging._nameToLevel[level.upper()]
|
|
|
|
root_logger = logging.getLogger()
|
|
if root_logger.level == level:
|
|
return
|
|
|
|
LOGGER.debug(f'Setting logging level: {level}')
|
|
root_logger.setLevel(level)
|
|
|
|
return
|