Update AzLogs to 2.0.1 and centralize rotated log filename handling
This commit is contained in:
+6
-12
@@ -35,6 +35,7 @@ from .core.file_manager import (
|
||||
from .core.log_system import LogLevel, create_module_logger
|
||||
from .core.log_system import logger as backend_log_controller
|
||||
from .core.log_system.config import LOG_LEVEL as BACKEND_DEFAULT_LOG_LEVEL
|
||||
from .core.log_system.logger import parse_rotated_log_filename
|
||||
from .core.path_utils import get_filename_from_path, get_metadata_sidecar_path, get_safe_metadata_sidecar_path
|
||||
|
||||
# Web directory for JavaScript interface
|
||||
@@ -5039,17 +5040,10 @@ class ModelResolverExtension:
|
||||
|
||||
def _backend_log_sort_key(path):
|
||||
name = os.path.basename(path)
|
||||
rotation = 0
|
||||
if ".log." in name:
|
||||
base_name, rotation_text = name.rsplit(".log.", 1)
|
||||
try:
|
||||
rotation = int(rotation_text)
|
||||
except ValueError:
|
||||
rotation = 999
|
||||
elif name.endswith(".log"):
|
||||
base_name = name[:-4]
|
||||
else:
|
||||
base_name = name
|
||||
parsed_name = parse_rotated_log_filename(name)
|
||||
if parsed_name is None:
|
||||
return (name.lower(), 999)
|
||||
base_name, rotation = parsed_name
|
||||
return (base_name.lower(), rotation)
|
||||
|
||||
def _collect_backend_log_files(log_dir):
|
||||
@@ -5061,7 +5055,7 @@ class ModelResolverExtension:
|
||||
name = str(entry or "")
|
||||
if not name.startswith("azlogs_"):
|
||||
continue
|
||||
if not (name.endswith(".log") or ".log." in name):
|
||||
if parse_rotated_log_filename(name) is None:
|
||||
continue
|
||||
|
||||
path = os.path.abspath(os.path.join(log_dir, name))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""
|
||||
AzLogs - Central logging system
|
||||
|
||||
Provides colored console logging, file rotation, and per-module log levels.
|
||||
@author: Azornes
|
||||
@title: AzLogs
|
||||
@version: 2.0.1
|
||||
@description: Logging Initializer
|
||||
"""
|
||||
|
||||
from .log_funcs import create_module_logger
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
@author: Azornes
|
||||
@title: AzLogs
|
||||
@version: 2.0.0
|
||||
@version: 2.0.1
|
||||
@description: Logging Configuration
|
||||
"""
|
||||
# Log level for development.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
@author: Azornes
|
||||
@title: AzLogs
|
||||
@version: 2.0.0
|
||||
@version: 2.0.1
|
||||
@description: Logging Initializer
|
||||
"""
|
||||
import logging
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
@author: Azornes
|
||||
@title: AzLogs
|
||||
@version: 2.0.0
|
||||
@version: 2.0.1
|
||||
@description: Logging Setup - Central logging system
|
||||
|
||||
Features:
|
||||
@@ -73,6 +73,26 @@ DEFAULT_CONFIG = {
|
||||
_WINDOWS_VT_PROCESSING_ENABLED = False
|
||||
|
||||
|
||||
def rotated_log_filename(default_name):
|
||||
"""Keep the .log extension at the end of rotated log filenames."""
|
||||
match = re.fullmatch(r"(.+)\.log\.(\d+)", str(default_name or ""))
|
||||
if not match:
|
||||
return default_name
|
||||
return f"{match.group(1)}.{match.group(2)}.log"
|
||||
|
||||
|
||||
def parse_rotated_log_filename(filename):
|
||||
"""Return the log family and rotation number for the current filename style."""
|
||||
name = os.path.basename(str(filename or ""))
|
||||
match = re.fullmatch(r"(.+)\.(\d+)\.log", name)
|
||||
if match:
|
||||
return match.group(1), int(match.group(2))
|
||||
|
||||
if name.endswith(".log"):
|
||||
return name[:-4], 0
|
||||
return None
|
||||
|
||||
|
||||
def _enable_windows_virtual_terminal_processing():
|
||||
"""Enable ANSI escape sequence handling for classic Windows consoles."""
|
||||
global _WINDOWS_VT_PROCESSING_ENABLED
|
||||
@@ -127,6 +147,7 @@ class SafeRotatingFileHandler(RotatingFileHandler):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._disabled_by_stream_error = False
|
||||
super().__init__(*args, **kwargs)
|
||||
self.namer = rotated_log_filename
|
||||
|
||||
def emit(self, record):
|
||||
if self._disabled_by_stream_error:
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from core.log_system.logger import (
|
||||
SafeRotatingFileHandler,
|
||||
parse_rotated_log_filename,
|
||||
rotated_log_filename,
|
||||
)
|
||||
|
||||
|
||||
class RotatedLogFilenameTests(unittest.TestCase):
|
||||
def test_places_rotation_before_log_extension(self):
|
||||
path = os.path.join("logs", "azlogs_MResolver.log.3")
|
||||
self.assertEqual(
|
||||
rotated_log_filename(path),
|
||||
os.path.join("logs", "azlogs_MResolver.3.log"),
|
||||
)
|
||||
|
||||
def test_leaves_unrelated_filename_unchanged(self):
|
||||
path = os.path.join("logs", "azlogs_MResolver.log")
|
||||
self.assertEqual(rotated_log_filename(path), path)
|
||||
|
||||
def test_parser_accepts_current_style(self):
|
||||
expected = ("azlogs_MResolver", 2)
|
||||
self.assertEqual(
|
||||
parse_rotated_log_filename("azlogs_MResolver.2.log"),
|
||||
expected,
|
||||
)
|
||||
self.assertEqual(
|
||||
parse_rotated_log_filename("azlogs_MResolver.log"),
|
||||
("azlogs_MResolver", 0),
|
||||
)
|
||||
|
||||
def test_parser_rejects_non_log_and_legacy_files(self):
|
||||
self.assertIsNone(parse_rotated_log_filename("other.txt"))
|
||||
self.assertIsNone(parse_rotated_log_filename("azlogs_MResolver.log.2"))
|
||||
self.assertIsNone(parse_rotated_log_filename("azlogs_MResolver.log2"))
|
||||
|
||||
|
||||
class SafeRotatingFileHandlerTests(unittest.TestCase):
|
||||
def test_rollover_keeps_log_as_the_final_extension(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
log_path = os.path.join(temp_dir, "azlogs_MResolver.log")
|
||||
logger = logging.getLogger(f"test-log-rotation-{id(self)}")
|
||||
logger.handlers.clear()
|
||||
logger.propagate = False
|
||||
logger.setLevel(logging.INFO)
|
||||
handler = SafeRotatingFileHandler(
|
||||
log_path,
|
||||
maxBytes=32,
|
||||
backupCount=2,
|
||||
encoding="utf-8",
|
||||
)
|
||||
handler.setFormatter(logging.Formatter("%(message)s"))
|
||||
logger.addHandler(handler)
|
||||
|
||||
try:
|
||||
logger.info("first message large enough to rotate")
|
||||
logger.info("second message large enough to rotate")
|
||||
logger.info("third message large enough to rotate")
|
||||
handler.flush()
|
||||
finally:
|
||||
logger.removeHandler(handler)
|
||||
handler.close()
|
||||
|
||||
files = set(os.listdir(temp_dir))
|
||||
self.assertIn("azlogs_MResolver.log", files)
|
||||
self.assertIn("azlogs_MResolver.1.log", files)
|
||||
self.assertIn("azlogs_MResolver.2.log", files)
|
||||
self.assertNotIn("azlogs_MResolver.3.log", files)
|
||||
self.assertNotIn("azlogs_MResolver.log.1", files)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user