🎨 Improved logging

- One unlimited log file per session
- Up to 3 session logs kept at any time
- Log compressed via lzma
This commit is contained in:
GeoffreyCoulaud
2023-06-12 23:11:09 +02:00
parent 2798097623
commit 68273d9217
2 changed files with 78 additions and 13 deletions

View File

@@ -0,0 +1,70 @@
import lzma
from io import StringIO
from logging import StreamHandler
from lzma import FORMAT_XZ, PRESET_DEFAULT
from os import PathLike
from pathlib import Path
class SessionFileHandler(StreamHandler):
"""
A logging handler that writes to a new file on every app restart.
The files are compressed and older sessions logs are kept up to a small limit.
"""
backup_count: int
filename: Path
log_file: StringIO = None
def create_dir(self) -> None:
"""Create the log dir if needed"""
self.filename.parent.mkdir(exist_ok=True)
def rotate_file(self, file: Path):
"""Rotate a file's number suffix and remove it if it's too old"""
# Skip non interesting dir entries
if not (file.is_file() and file.name.startswith(self.filename.name)):
return
# Compute the new number suffix
suffixes = file.suffixes
has_number = len(suffixes) != len(self.filename.suffixes)
current_number = 0 if not has_number else int(suffixes[-1][1:])
new_number = current_number + 1
# Rename with new number suffix
if has_number:
suffixes.pop()
suffixes.append(f".{new_number}")
stem = file.name.split(".", maxsplit=1)[0]
new_name = stem + "".join(suffixes)
print(f"Log file renamed: {file.name} -> {new_name}")
file = file.rename(file.with_name(new_name))
# Remove older files
if new_number > self.backup_count:
print(f"Log file deleted: {file.name}")
file.unlink()
return
def rotate(self) -> None:
"""Rotate the numbered suffix on the log files and remove old ones"""
files = list(self.filename.parent.iterdir())
files.sort(key=lambda file: file.name, reverse=True)
for file in files:
self.rotate_file(file)
def __init__(self, filename: PathLike, backup_count: int = 2) -> None:
self.filename = Path(filename)
self.backup_count = backup_count
self.create_dir()
self.rotate()
self.log_file = lzma.open(
self.filename, "at", format=FORMAT_XZ, preset=PRESET_DEFAULT
)
super().__init__(self.log_file)
def close(self) -> None:
self.log_file.close()
super().close()

View File

@@ -8,18 +8,14 @@ from src import shared
def setup_logging(): def setup_logging():
"""Intitate the app's logging""" """Intitate the app's logging"""
# Prepare the log file is_dev = shared.PROFILE == "development"
log_dir = shared.data_dir / "cartridges" / "logs" profile_app_log_level = "DEBUG" if is_dev else "INFO"
log_dir.mkdir(exist_ok=True) profile_lib_log_level = "INFO" if is_dev else "WARNING"
log_file_path = log_dir / "cartridges.log"
log_file_max_size_bytes = 8 * 10**6 # 8 MB
# Define log levels
profile_app_log_level = "DEBUG" if shared.PROFILE == "development" else "INFO"
profile_lib_log_level = "INFO" if shared.PROFILE == "development" else "WARNING"
app_log_level = os.environ.get("LOGLEVEL", profile_app_log_level).upper() app_log_level = os.environ.get("LOGLEVEL", profile_app_log_level).upper()
lib_log_level = os.environ.get("LIBLOGLEVEL", profile_lib_log_level).upper() lib_log_level = os.environ.get("LIBLOGLEVEL", profile_lib_log_level).upper()
log_filename = shared.data_dir / "cartridges" / "logs" / "cartridges.log.xz"
config = { config = {
"version": 1, "version": 1,
"formatters": { "formatters": {
@@ -33,12 +29,11 @@ def setup_logging():
}, },
"handlers": { "handlers": {
"file_handler": { "file_handler": {
"class": "logging.handlers.RotatingFileHandler", "class": "src.logging.session_file_handler.SessionFileHandler",
"formatter": "file_formatter", "formatter": "file_formatter",
"level": "DEBUG", "level": "DEBUG",
"filename": log_file_path, "filename": log_filename,
"maxBytes": log_file_max_size_bytes, "backup_count": 2,
"backupCount": 1,
}, },
"app_console_handler": { "app_console_handler": {
"class": "logging.StreamHandler", "class": "logging.StreamHandler",