2021-04-26 21:53:40 +02:00
|
|
|
"""This module contains the logging module."""
|
|
|
|
from typing import Union
|
|
|
|
from pathlib import Path
|
|
|
|
from datetime import datetime
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
class Logger:
|
|
|
|
"""A logger class that logs, ya get the point."""
|
|
|
|
|
|
|
|
LOG_LEVELS = [
|
|
|
|
"debug",
|
|
|
|
"info",
|
|
|
|
"warning",
|
|
|
|
"error",
|
|
|
|
"critical",
|
|
|
|
]
|
|
|
|
"""The log levels' names.
|
|
|
|
|
|
|
|
When used as arguments, the counting starts at 1
|
|
|
|
instead of 0.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
log_file: Union[Path, str] = None,
|
|
|
|
append: bool = True,
|
|
|
|
stdout: bool = True,
|
|
|
|
log_level: int = 3,
|
|
|
|
):
|
|
|
|
"""Initialize a new Logger object.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
log_file: path to a log file. If any of the folders within the log
|
|
|
|
file's path don't exist, they will get created. If no value is
|
|
|
|
specified, no log file is created.
|
|
|
|
append: wether or not to append to the existing file or overwrite
|
|
|
|
it. If False, the original file gets deleted during init.
|
|
|
|
stdout: wether or not to log to stdout as well
|
|
|
|
log_level: the minimum level to log
|
|
|
|
"""
|
|
|
|
self.log_file = Path(log_file) if log_file else None
|
|
|
|
self.stdout = stdout
|
|
|
|
self.log_level = log_level
|
|
|
|
|
|
|
|
# Remove the original log file
|
|
|
|
if not append:
|
|
|
|
self.log_file.unlink(missing_ok=True)
|
|
|
|
|
2021-04-26 22:34:12 +02:00
|
|
|
def custom(self, message: str, header: str = None):
|
|
|
|
"""Log a message given a header and a message.
|
|
|
|
|
|
|
|
If a header is provided (aka truthy), the final form of the messsage
|
|
|
|
wil be:
|
|
|
|
|
|
|
|
`[YYYY-MM-DD HH:MM:SS][header] message`
|
|
|
|
|
|
|
|
Otherwise, it's just:
|
|
|
|
|
|
|
|
`[YYYY-MM-DD HH:MM:SS] message`
|
|
|
|
|
|
|
|
Args:
|
|
|
|
message: the message to display
|
|
|
|
header: the header to add to the message
|
|
|
|
"""
|
|
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
log_message = f"[{timestamp}] {message}\n"
|
|
|
|
|
|
|
|
if header:
|
|
|
|
log_message = f"[{timestamp}][{header}] {message}\n"
|
|
|
|
|
|
|
|
if self.log_file:
|
|
|
|
self.log_file.write_text(log_message)
|
|
|
|
|
|
|
|
if self.stdout:
|
|
|
|
sys.stdout.write(log_message)
|
|
|
|
|
2021-04-26 21:53:40 +02:00
|
|
|
def log(self, level: int, message: str):
|
|
|
|
"""Log a message with a specific level.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
level: log level (index in the LOG_LEVELS variable)
|
|
|
|
message: the message to log
|
|
|
|
"""
|
|
|
|
if level < self.log_level:
|
|
|
|
return
|
|
|
|
|
|
|
|
level_name = self.LOG_LEVELS[level - 1].upper()
|
2021-04-26 22:34:12 +02:00
|
|
|
self.custom(level_name, message)
|
2021-04-26 21:53:40 +02:00
|
|
|
|
|
|
|
def debug(self, message: str):
|
|
|
|
"""Log a debug message."""
|
|
|
|
self.log(1, message)
|
|
|
|
|
|
|
|
def info(self, message: str):
|
|
|
|
"""Log an info message."""
|
|
|
|
self.log(2, message)
|
|
|
|
|
|
|
|
def warning(self, message: str):
|
|
|
|
"""Log a warning message."""
|
|
|
|
self.log(3, message)
|
|
|
|
|
|
|
|
def error(self, message: str):
|
|
|
|
"""Log an error message."""
|
|
|
|
self.log(4, message)
|
|
|
|
|
|
|
|
def critical(self, message: str):
|
|
|
|
"""Log a critical message."""
|
|
|
|
self.log(5, message)
|