Merge pull request #121 from kra-mo/v2-logging
This commit is contained in:
@@ -33,6 +33,8 @@ class SessionFileHandler(StreamHandler):
|
|||||||
The files are compressed and older sessions logs are kept up to a small limit.
|
The files are compressed and older sessions logs are kept up to a small limit.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NUMBER_SUFFIX_POSITION = 1
|
||||||
|
|
||||||
backup_count: int
|
backup_count: int
|
||||||
filename: Path
|
filename: Path
|
||||||
log_file: StringIO = None
|
log_file: StringIO = None
|
||||||
@@ -41,50 +43,75 @@ class SessionFileHandler(StreamHandler):
|
|||||||
"""Create the log dir if needed"""
|
"""Create the log dir if needed"""
|
||||||
self.filename.parent.mkdir(exist_ok=True, parents=True)
|
self.filename.parent.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
def path_is_logfile(self, path: Path) -> bool:
|
||||||
|
return path.is_file() and path.name.startswith(self.filename.stem)
|
||||||
|
|
||||||
|
def path_has_number(self, path: Path) -> bool:
|
||||||
|
try:
|
||||||
|
int(path.suffixes[self.NUMBER_SUFFIX_POSITION][1:])
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_path_number(self, path: Path) -> int:
|
||||||
|
"""Get the number extension in the filename as an int"""
|
||||||
|
suffixes = path.suffixes
|
||||||
|
number = (
|
||||||
|
0
|
||||||
|
if not self.path_has_number(path)
|
||||||
|
else int(suffixes[self.NUMBER_SUFFIX_POSITION][1:])
|
||||||
|
)
|
||||||
|
return number
|
||||||
|
|
||||||
|
def set_path_number(self, path: Path, number: int) -> str:
|
||||||
|
"""Set or add the number extension in the filename"""
|
||||||
|
suffixes = path.suffixes
|
||||||
|
if self.path_has_number(path):
|
||||||
|
suffixes.pop(self.NUMBER_SUFFIX_POSITION)
|
||||||
|
suffixes.insert(self.NUMBER_SUFFIX_POSITION, f".{number}")
|
||||||
|
stem = path.name.split(".", maxsplit=1)[0]
|
||||||
|
new_name = stem + "".join(suffixes)
|
||||||
|
return new_name
|
||||||
|
|
||||||
|
def file_sort_key(self, path: Path) -> int:
|
||||||
|
"""Key function used to sort files"""
|
||||||
|
return self.get_path_number(path) if self.path_has_number(path) else 0
|
||||||
|
|
||||||
|
def get_logfiles(self) -> list[Path]:
|
||||||
|
"""Get the log files"""
|
||||||
|
logfiles = list(filter(self.path_is_logfile, self.filename.parent.iterdir()))
|
||||||
|
logfiles.sort(key=self.file_sort_key, reverse=True)
|
||||||
|
return logfiles
|
||||||
|
|
||||||
def rotate_file(self, path: Path):
|
def rotate_file(self, path: Path):
|
||||||
"""Rotate a file's number suffix and remove it if it's too old"""
|
"""Rotate a file's number suffix and remove it if it's too old"""
|
||||||
|
|
||||||
# Skip non interesting dir entries
|
# If uncompressed, compress
|
||||||
if not (path.is_file() and path.name.startswith(self.filename.name)):
|
if not path.name.endswith(".xz"):
|
||||||
return
|
new_path = path.with_suffix(path.suffix + ".xz")
|
||||||
|
with (
|
||||||
# Compute the new number suffix
|
lzma.open(
|
||||||
suffixes = path.suffixes
|
new_path, "wt", format=FORMAT_XZ, preset=PRESET_DEFAULT
|
||||||
has_number = len(suffixes) != len(self.filename.suffixes)
|
) as lzma_file,
|
||||||
current_number = 0 if not has_number else int(suffixes[-1][1:])
|
open(path, "r", encoding="utf-8") as original_file,
|
||||||
new_number = current_number + 1
|
):
|
||||||
|
lzma_file.write(original_file.read())
|
||||||
|
path.unlink()
|
||||||
|
path = new_path
|
||||||
|
|
||||||
# Rename with new number suffix
|
# Rename with new number suffix
|
||||||
if has_number:
|
new_number = self.get_path_number(path) + 1
|
||||||
suffixes.pop()
|
new_path_name = self.set_path_number(path, new_number)
|
||||||
suffixes.append(f".{new_number}")
|
path = path.rename(path.with_name(new_path_name))
|
||||||
stem = path.name.split(".", maxsplit=1)[0]
|
|
||||||
new_name = stem + "".join(suffixes)
|
|
||||||
path = path.rename(path.with_name(new_name))
|
|
||||||
|
|
||||||
# Remove older files
|
# Remove older files
|
||||||
if new_number > self.backup_count:
|
if new_number > self.backup_count:
|
||||||
path.unlink()
|
path.unlink()
|
||||||
return
|
return
|
||||||
|
|
||||||
def file_sort_key(self, path: Path) -> int:
|
|
||||||
"""Key function used to sort files"""
|
|
||||||
if not path.name.startswith(self.filename.name):
|
|
||||||
# First all files that aren't logs
|
|
||||||
return -1
|
|
||||||
if path.name == self.filename.name:
|
|
||||||
# Then the latest log file
|
|
||||||
return 0
|
|
||||||
# Then in order the other log files
|
|
||||||
return int(path.suffixes[-1][1:])
|
|
||||||
|
|
||||||
def get_files(self) -> list[Path]:
|
|
||||||
return list(self.filename.parent.iterdir())
|
|
||||||
|
|
||||||
def rotate(self) -> None:
|
def rotate(self) -> None:
|
||||||
"""Rotate the numbered suffix on the log files and remove old ones"""
|
"""Rotate the numbered suffix on the log files and remove old ones"""
|
||||||
(files := self.get_files()).sort(key=self.file_sort_key, reverse=True)
|
for path in self.get_logfiles():
|
||||||
for path in files:
|
|
||||||
self.rotate_file(path)
|
self.rotate_file(path)
|
||||||
|
|
||||||
def __init__(self, filename: PathLike, backup_count: int = 2) -> None:
|
def __init__(self, filename: PathLike, backup_count: int = 2) -> None:
|
||||||
@@ -92,10 +119,8 @@ class SessionFileHandler(StreamHandler):
|
|||||||
self.backup_count = backup_count
|
self.backup_count = backup_count
|
||||||
self.create_dir()
|
self.create_dir()
|
||||||
self.rotate()
|
self.rotate()
|
||||||
shared.log_files = self.get_files()
|
shared.log_files = self.get_logfiles()
|
||||||
self.log_file = lzma.open(
|
self.log_file = open(self.filename, "w", encoding="utf-8")
|
||||||
self.filename, "at", format=FORMAT_XZ, preset=PRESET_DEFAULT
|
|
||||||
)
|
|
||||||
super().__init__(self.log_file)
|
super().__init__(self.log_file)
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ def setup_logging():
|
|||||||
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.cache_dir / "cartridges" / "logs" / "cartridges.log.xz"
|
log_filename = shared.cache_dir / "cartridges" / "logs" / "cartridges.log"
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
|
|||||||
14
src/main.py
14
src/main.py
@@ -143,10 +143,20 @@ class CartridgesApplication(Adw.Application):
|
|||||||
shared.store.add_game(game, {"skip_save": True})
|
shared.store.add_game(game, {"skip_save": True})
|
||||||
|
|
||||||
def on_about_action(self, *_args):
|
def on_about_action(self, *_args):
|
||||||
|
# Get the debug info from the log files
|
||||||
debug_str = ""
|
debug_str = ""
|
||||||
for path in shared.log_files:
|
for i, path in enumerate(shared.log_files):
|
||||||
log_file = lzma.open(path, "rt", encoding="utf-8")
|
# Add a horizontal line between runs
|
||||||
|
if i > 0:
|
||||||
|
debug_str += "─" * 37 + "\n"
|
||||||
|
# Add the run's logs
|
||||||
|
log_file = (
|
||||||
|
lzma.open(path, "rt", encoding="utf-8")
|
||||||
|
if path.name.endswith(".xz")
|
||||||
|
else open(path, "r", encoding="utf-8")
|
||||||
|
)
|
||||||
debug_str += log_file.read()
|
debug_str += log_file.read()
|
||||||
|
log_file.close()
|
||||||
|
|
||||||
about = Adw.AboutWindow(
|
about = Adw.AboutWindow(
|
||||||
transient_for=self.win,
|
transient_for=self.win,
|
||||||
|
|||||||
Reference in New Issue
Block a user