Source code for duck.cli.commands.logs

"""
Module containing the LogsCommand class for Duck project log management.
"""
import os
import click

from pathlib import Path
from typing import List

from duck.logging import console


[docs] class LogsCommand: """ CLI command group for managing Duck project logs. """
[docs] @classmethod def get_logs_dir(cls) -> Path: """ Get the resolved path to the project's logs directory. """ from duck.settings import SETTINGS logsdir = SETTINGS['LOGGING_DIR'] return Path(logsdir).resolve() if not isinstance(logsdir, Path) else logsdir.resolve()
[docs] @classmethod def _get_log_files(cls) -> List[Path]: """ Return a list of log file paths in the logs directory. """ logsdir = cls.get_logs_dir() if not logsdir.exists(): console.log_raw(f"Log directory not found: {logsdir}", level=console.WARNING) return [] return [p for p in logsdir.iterdir() if p.is_file()]
[docs] @staticmethod def _sort_logs(logs: List[Path], sort: str) -> List[Path]: """ Sort logs based on criteria. """ if sort == "oldest": return sorted(logs, key=lambda f: f.stat().st_mtime) elif sort == "newest": return sorted(logs, key=lambda f: f.stat().st_mtime, reverse=True) elif sort == "largest": return sorted(logs, key=lambda f: f.stat().st_size, reverse=True) else: console.log_raw(f"Unknown sort type '{sort}', defaulting to 'oldest'.", level=console.WARNING) return sorted(logs, key=lambda f: f.stat().st_mtime)
[docs] @classmethod def list_logs(cls, max: int = -1, sort: str = "oldest", show_size: bool = False): """ List Duck project logs. """ logs = cls._get_log_files() maxlogs = max if not logs: console.log_raw("No logs found.", level=console.WARNING) return logs = cls._sort_logs(logs, sort) if maxlogs > 0: logs = logs[:maxlogs] for log in logs: size_info = f" ({log.stat().st_size / 1024:.2f} KB)" if show_size else "" console.log_raw(f"{log.name}{size_info}", custom_color=console.Fore.GREEN)
[docs] @classmethod def purge_logs(cls, max: int = -1, sort: str = "oldest"): """ Delete logs, optionally limited by count and sorted by criteria. """ logs = cls._get_log_files() maxlogs = max if not logs: console.log_raw("No logs to delete", level=console.WARNING) return logs = cls._sort_logs(logs, sort) if maxlogs > 0: logs = logs[:maxlogs] for log in logs: try: log.unlink() console.log_raw(f"Deleted {log.name}", level=console.WARNING) except OSError as e: console.print(f"Failed to delete {log.name}: {e}", level=console.ERROR)
[docs] @classmethod def count_logs(cls): """ Count the number of log files. """ logs = cls._get_log_files() console.log_raw(f"{len(logs)} log(s) found.", level=console.DEBUG)
[docs] @classmethod def get_logs_size(cls, fmt: str = "kb"): """ Get the total size of all logs. """ logs = cls._get_log_files() total_size = sum(log.stat().st_size for log in logs) unit_map = {"b": 1, "kb": 1024, "mb": 1024**2, "gb": 1024**3} fmt = fmt.lower() divisor = unit_map.get(fmt, 1024) formatted_size = total_size / divisor # Print to console console.log_raw(f"Total logs size: {formatted_size:.2f} {fmt.upper()}", level=console.DEBUG)
[docs] @classmethod def register_subcommands(cls, main_command: click.Command): """ Register the log management subcommands. """ data = { "list": { "callback": cls.list_logs, "params": [ click.Option(('-n', "--max"), type=int, default=-1, help="Max number of logs."), click.Option(("-s", "--sort"), type=str, default="oldest", help="Sort: oldest, newest, largest."), click.Option(("-ss", "--show-size"), is_flag=True, default=False, help="Show log sizes."), ], "help": "List project logs." }, "purge": { "callback": cls.purge_logs, "params": [ click.Option(('-n', "--max"), type=int, default=-1, help="Max number of logs."), click.Option(("-s", "--sort"), type=str, default="oldest", help="Sort: oldest, newest, largest."), ], "help": "Delete project logs." }, "count": { "callback": cls.count_logs, "params": [], "help": "Count the number of logs." }, "size": { "callback": cls.get_logs_size, "params": [ click.Option(('-f', "--fmt"), type=str, default="kb", help="Size unit: b, kb, mb, gb."), ], "help": "Get the total size of logs." }, } for cmd_name, info in data.items(): cmd = click.Command(cmd_name, callback=info["callback"], params=info["params"], help=info["help"]) main_command.add_command(cmd)