From bf858811a1e3e95760494b6236ae89c7cb047350 Mon Sep 17 00:00:00 2001 From: sexfrance Date: Sat, 9 Nov 2024 20:15:43 +0100 Subject: [PATCH] Added LogLevel support and updated version to 2.0.0; enhanced test suite with comprehensive logging and loader features --- README.md | 204 +++++++++++++++------------------- logmagix/__init__.py | 2 +- logmagix/logger.py | 256 +++++++++++++++++++++++++++++++++++-------- setup.py | 2 +- test.py | 109 +++++++++++++----- 5 files changed, 385 insertions(+), 188 deletions(-) diff --git a/README.md b/README.md index 824be9f..6a21f30 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ # LogMagix -**LogMagix** is a custom Python logging package that offers styled, colorful log messages for various logging levels such as success, warning, failure, and more. It also features an animated loader class for providing a visual indicator during long-running operations in the terminal. Additionally, the new `Home` class offers customizable ASCII art displays for greeting users with special messages, branding, or system information. +**LogMagix** is a custom Python logging package that provides styled, colorful log messages for various logging levels, such as success, warning, failure, and more. It includes advanced features such as batch logging, file logging, customizable animated loaders, and ASCII art displays through the `Home` class, perfect for adding visual appeal to terminal-based applications. ## 🔥 Features -- Log messages for success, warning, failure, and informational levels. -- Customize message colors using ANSI escape sequences. -- Time-stamped log messages for better tracking. -- Built-in animated loader for visually appealing loading spinners. -- Customizable log and loader prefixes. -- ASCII art display for personalized greetings, system info, and branding. -- Simple and flexible API with multiple ways to use the `Loader` class. -- Customizable text alignment for the `Home` ASCII art display. +- **Enhanced Logging Levels**: Support for `LogLevel` enumeration, including `DEBUG`, `INFO`, `WARNING`, `SUCCESS`, `ERROR`, and `CRITICAL`, allowing fine-grained control over log output. +- **Batch Logging Mode**: Queue messages to batch display them at once. +- **File Logging**: Optionally log messages to a file with rotating log handlers. +- **Color Customization**: ANSI escape sequences for colorful terminal output. +- **Timestamped Messages**: Precise logging with time-based messages. +- **Loader with Animation**: Built-in animated loader for long-running operations with customizable text and style. +- **ASCII Art Display**: Display ASCII art with custom messages, branding, or system information. +- **User Welcome**: Personalized greetings in the ASCII art screen. ## ⚙️ Installation -To install the package locally, clone the repository and run: +Install LogMagix locally: ```bash pip install . ``` -You can also install it via `pip` from PyPI: +Or via PyPI: ```bash pip install logmagix @@ -32,175 +32,151 @@ pip install logmagix ### Importing the Package ```python -from logmagix import Logger, Loader, Home +from logmagix import Logger, Loader, Home, LogLevel ``` ### Logging -Initialize the `Logger` class to log messages with different levels: +Initialize the `Logger` class and log messages at different levels. You can now also set the minimum log level, batch log messages, and write them to a file: ```python -log = Logger() +log = Logger(log_file="app.log", prefix="myapp/logs") -# Success message -log.success("Operation completed successfully!") +# Set minimum log level to control the output (optional) +log.set_min_level(LogLevel.INFO) -# Failure message +# Log levels +log.success("Operation completed successfully!") log.failure("Something went wrong!") - -# Warning message log.warning("This is a warning!") - -# Informational message log.info("Informational log message") - -# Debug message log.debug("Debugging log message") - -# Customizable message -log.message("Dad", f"How are you? I'm gonna come soon!", start="", end="") # Start and end optional - -# Question input -log.question("This is an input question!") +log.critical("Critical error encountered", exit_code=1) # Exits after logging +log.message("Custom", "Custom message with prefix") + +# Batch Logging Example +log.batch() # Start batch mode +log.success("Batch message 1") +log.info("Batch message 2") +log.flush() # Output all batched messages ``` -### Loading Animation - -The `Loader` class can be used in two ways: +### File Logging -#### Using a context manager: +Save logs to a file with rotation options: ```python -from time import sleep - -with Loader(desc="Loading with context manager..."): - for i in range(10): - sleep(0.25) -``` - -#### Using `start()` and `stop()` methods: - -```python -loader = Loader(desc="Loading with object...", end="That was fast!", timeout=0.05).start() -for i in range(10): - sleep(0.25) -loader.stop() +log = Logger( + log_file="my_app.log", + max_file_size=5_000_000, # 5MB max file size + backup_count=3 # Keep 3 backup files +) +log.info("Logging to file with rotation setup!") ``` -### Custom Log and Loader Prefix +### Loading Animation -Both the `Logger` and `Loader` classes allow for customizing the prefix that is shown before each message: +Use the `Loader` class in two ways: -#### Logger Prefix: +1. **Context Manager**: -```python -log = Logger(prefix=".myapp/logs") -log.success("This message has a custom log prefix!") -``` + ```python + from time import sleep -#### Loader Prefix: + with Loader(desc="Loading data..."): + sleep(2) + ``` -```python -loader = Loader(prefix=".myapp/loader", desc="Loading with a custom loader prefix...") -loader.start() -time.sleep(5) # Simulate a task -loader.stop() -``` +2. **Start/Stop Methods**: -### ASCII Art and Greeting (New `Home` Class) + ```python + loader = Loader(desc="Saving files...", end="Done!").start() + sleep(2) + loader.stop() + ``` -The `Home` class lets you display customized ASCII art text along with system information, such as a welcome message, username, or credits. +### ASCII Art and Welcome Display -#### Using the `Home` Class: +The `Home` class allows you to display ASCII art along with user greetings and system information. ```python home_screen = Home( text="LogMagix", align="center", - adinfo1="discord.cyberious.xyz", - adinfo2="v1.0", - credits="Developed by sexfrance", - clear = False, # To clear the console, default is True + adinfo1="logmagix.io", + adinfo2="v1.2", + credits="Developed by sexfrance" ) - home_screen.display() ``` -This will display the ASCII art version of "LogMagix" in the center of the terminal, along with optional `adinfo1` and `adinfo2` texts at the bottom. The terminal width is automatically detected to align the text properly. - ### Full Example -Here’s an example showing both logging, loader, and the new `Home` class functionality: +Here’s an example showing logging, loader, and the `Home` ASCII art functionality: ```python from logmagix import Logger, Loader, Home import time -import uuid -log = Logger(prefix="custom/log/prefix") -start_time = time.time() +log = Logger(log_file="app.log", prefix="myapp") -# Log messages +# Logging log.success("Everything is running smoothly!") -log.warning("Watch out, something might happen!") -log.failure("Critical error occurred!") -log.info("System is working properly") -log.debug(f"The system uuid is {uuid.getnode()}") -log.message("Dad", f"How are you? I'm gonna come soon!", start=start_time, end=time.time()) -log.question("How old are you? ") - - -# Use loader with custom prefix and context manager -with Loader(prefix="custom/loader/prefix", desc="Processing data..."): - time.sleep(2) # Simulate task - -# Use loader with custom prefix and start/stop methods -loader = Loader(prefix="custom/loader/prefix", desc="Saving files...", end="Done !", timeout=0.05).start() -time.sleep(2) # Simulate task -loader.stop() +log.warning("This is just a warning!") +log.failure("A critical error occurred.") +log.debug("System debug message") +# Loader with context manager +with Loader(prefix="myapp/loader", desc="Processing data..."): + time.sleep(2) +# ASCII Art Home screen home_screen = Home( text="LogMagix", align="center", - adinfo1="discord.cyberious.xyz", - adinfo2="v1.0", + adinfo1="https://logmagix.io", + adinfo2="v1.2", credits="Developed by sexfrance" ) - home_screen.display() +``` +## 🛠️ Configuration Options -log.success("Processing completed!") -``` +### Logger -### Customization in `Home` Class +- **Log Levels**: Control which levels to log using `LogLevel` enumeration, including `DEBUG`, `INFO`, `WARNING`, `SUCCESS`, `ERROR`, and `CRITICAL`. Set a minimum level to ignore lower-priority messages. +- **prefix**: Custom prefix before each log message. +- **log_file**: File path to log messages. +- **max_file_size**: Maximum size for log files (default is 10MB). +- **backup_count**: Number of backup log files to keep. -- **text**: The text to be displayed in ASCII art. -- **align**: Align the ASCII art text to "left", "center", or "right" in the terminal. -- **adinfo1** and **adinfo2**: Additional information displayed below the ASCII art. -- **credits**: Optional credits or user information. +### Loader -## ❗ Requirements +- **desc**: Description displayed alongside the loading animation. +- **end**: Text displayed after the loader stops. +- **timeout**: Delay between animation frames (in seconds). -LogMagix requires: +### Home -- `colorama` for cross-platform color support in the terminal. -- `pystyle` for creating the colored text effects. +- **text**: ASCII text to display. +- **align**: Text alignment in the terminal ("left", "center", "right"). +- **adinfo1 / adinfo2**: Additional info displayed below the ASCII art. +- **credits**: Custom credits or developer name. -To install dependencies, run: +## 🖥️ Contributing -```bash -pip install colorama pystyle -``` +Contributions are welcome! To contribute: -## ©️ License +1. Fork the repository. +2. Make your changes. +3. Submit a pull request for review. -LogMagix is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. +For major changes, please open an issue first to discuss what you’d like to change. -## 🖥️ Contributing +## ©️ License -Contributions are welcome! Feel free to fork the repository, make changes, and submit a pull request. +LogMagix is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. ## 👤 Author diff --git a/logmagix/__init__.py b/logmagix/__init__.py index e386202..fee3654 100644 --- a/logmagix/__init__.py +++ b/logmagix/__init__.py @@ -1,3 +1,3 @@ # logmagix/__init__.py -from .logger import Logger, Loader, Home +from .logger import Logger, Loader, Home, LogLevel diff --git a/logmagix/logger.py b/logmagix/logger.py index 853b7a3..6355afa 100644 --- a/logmagix/logger.py +++ b/logmagix/logger.py @@ -1,79 +1,239 @@ import datetime import time -from threading import Thread +from threading import Thread, Lock from itertools import cycle +from enum import Enum +from typing import Optional, List +import logging.handlers from colorama import Fore, Style import os +from sys import exit import getpass from .font import ascii_art -from pystyle import Write, System, Colors +from pystyle import Write, Colors + +class LogLevel(Enum): + """Enumeration of available logging levels.""" + DEBUG = 0 + INFO = 1 + WARNING = 2 + SUCCESS = 3 + ERROR = 4 + CRITICAL = 5 class Logger: - def __init__(self, prefix: str | None = "discord.cyberious.xyz"): - self.WHITE = "\u001b[37m" - self.MAGENTA = "\033[38;5;97m" - self.MAGENTAA = "\033[38;2;157;38;255m" - self.RED = "\033[38;5;196m" - self.GREEN = "\033[38;5;40m" - self.YELLOW = "\033[38;5;220m" - self.BLUE = "\033[38;5;21m" - self.PINK = "\033[38;5;176m" - self.CYAN = "\033[96m" + """Advanced logging system with color support and multiple output formats.""" + + COLORS = { + "WHITE": "\u001b[37m", + "MAGENTA": "\033[38;5;97m", + "MAGENTA_BRIGHT": "\033[38;2;157;38;255m", + "RED": "\033[38;5;196m", + "LIGHT_CORAL": "\033[38;5;210m", + "GREEN": "\033[38;5;40m", + "YELLOW": "\033[38;5;220m", + "BLUE": "\033[38;5;21m", + "PINK": "\033[38;5;176m", + "CYAN": "\033[96m" + } + + def __init__( + self, + prefix: Optional[str] = "discord.cyberious.xyz", + log_file: Optional[str] = None, + max_file_size: int = 10_000_000, + backup_count: int = 5 + ) -> None: + """Initialize the logger with the given configuration.""" + self._setup_colors() self.prefix = f"{self.PINK}[{self.MAGENTA}{prefix}{self.PINK}] " if prefix else f"{self.PINK}" + self.log_lock = Lock() + self.message_buffer: List[tuple] = [] + self._min_level = LogLevel.DEBUG + self._batch_messages = [] + self._batch_mode = False + + self.file_handler = self._setup_file_handler(log_file, max_file_size, backup_count) if log_file else None + + def _setup_colors(self) -> None: + """Set up color attributes from COLORS dictionary.""" + for name, value in self.COLORS.items(): + setattr(self, name, value) + + def _setup_file_handler( + self, + log_file: str, + max_file_size: int, + backup_count: int + ) -> logging.handlers.RotatingFileHandler: + """Configure and return a file handler for logging.""" + handler = logging.handlers.RotatingFileHandler( + log_file, + maxBytes=max_file_size, + backupCount=backup_count + ) + handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) + return handler + + def set_min_level(self, level: LogLevel) -> None: + """Set minimum log level. Messages below this level will not be displayed.""" + if not isinstance(level, LogLevel): + raise ValueError("Level must be a LogLevel enum value") + self._min_level = level + + def _should_log(self, level): + """Check if message should be logged based on minimum level.""" + return level.value >= self._min_level.value + + def batch(self) -> None: + """Start batch logging - messages will be stored but not displayed""" + self._batch_mode = True + self._batch_messages = [] + + def flush(self) -> None: + """Flush all stored messages and display them""" + if not self._batch_mode: + return + + with self.log_lock: + for msg_data in self._batch_messages: + level_str, color, message = msg_data + display_level = level_str.capitalize() + print(self.message3(f"{color}{display_level}", f"{color}{message}")) + if self.file_handler: + level = getattr(LogLevel, level_str) + self._log_to_file(level, message) + self._batch_messages.clear() + self._batch_mode = False + + def _log(self, level: LogLevel, message: str, start: int = None, end: int = None) -> None: + """Internal logging method that handles both console and file output.""" + if not self._should_log(level): + return - def get_time(self) -> str: - return datetime.datetime.now().strftime("%H:%M:%S") - - def message3(self, level: str, message: str, start: int = None, end: int = None) -> str: - time = self.get_time() - return f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}] {self.PINK}[{self.CYAN}{level}{self.PINK}] -> {self.CYAN}{message}{Fore.RESET}" + # Map log levels to colors and display names + level_colors = { + LogLevel.DEBUG: self.BLUE, + LogLevel.INFO: self.CYAN, + LogLevel.WARNING: self.YELLOW, + LogLevel.SUCCESS: self.GREEN, + LogLevel.ERROR: self.RED, + LogLevel.CRITICAL: self.LIGHT_CORAL + } + + color = level_colors.get(level, self.WHITE) + formatted_message = self.message3(f"{color}{level.name}", f"{color}{message}", start, end) + + with self.log_lock: + print(formatted_message) + if self.file_handler: + stripped_message = self._strip_colors(formatted_message) + self.file_handler.emit( + logging.LogRecord( + name="logger", + level=level.value * 10, + pathname="", + lineno=0, + msg=stripped_message, + args=(), + exc_info=None + ) + ) + + def _strip_colors(self, message: str) -> str: + """Remove ANSI color codes from message.""" + import re + return re.sub(r'\033\[[0-9;]*m', '', message) def success(self, message: str, start: int = None, end: int = None, level: str = "Success") -> None: - print(self.message3(f"{self.GREEN}{level}", f"{self.GREEN}{message}", start, end)) + if self._should_log(LogLevel.SUCCESS): + self._log(LogLevel.SUCCESS, message, start, end) def failure(self, message: str, start: int = None, end: int = None, level: str = "Failure") -> None: - print(self.message3(f"{self.RED}{level}", f"{self.RED}{message}", start, end)) + if self._should_log(LogLevel.ERROR): + self._log(LogLevel.ERROR, message, start, end) + + def critical(self, message: str, start: int = None, end: int = None, level: str = "CRITICAL", exit_code: int = 1) -> None: + input(self.message3(f"{self.LIGHT_CORAL}{level}", f"{self.LIGHT_CORAL}{message}", start, end)) + self._log_to_file(LogLevel.CRITICAL, message) + exit(exit_code) def warning(self, message: str, start: int = None, end: int = None, level: str = "Warning") -> None: - print(self.message3(f"{self.YELLOW}{level}", f"{self.YELLOW}{message}", start, end)) + if self._should_log(LogLevel.WARNING): + self._log(LogLevel.WARNING, message, start, end) + + def info(self, message: str, start: int = None, end: int = None) -> None: + if self._should_log(LogLevel.INFO): + self._log(LogLevel.INFO, message, start, end) + + def debug(self, message: str, start: int = None, end: int = None) -> None: + if self._should_log(LogLevel.DEBUG): + self._log(LogLevel.DEBUG, message, start, end) + + def _log_to_file(self, level: LogLevel, message: str) -> None: + """Helper method to handle file logging""" + if not self.file_handler: + return + + if level.value >= self._min_level.value: + stripped_message = self._strip_colors(message) + self.file_handler.emit( + logging.LogRecord( + name="logger", + level=level.value * 10, + pathname="", + lineno=0, + msg=stripped_message, + args=(), + exc_info=None + ) + ) + + def get_time(self) -> str: + return datetime.datetime.now().strftime("%H:%M:%S") def message(self, level: str, message: str, start: int = None, end: int = None) -> None: time = self.get_time() - timer = f" {self.MAGENTAA}In{self.WHITE} -> {self.MAGENTAA}{str(end - start)[:5]} Seconds {Fore.RESET}" if start and end else "" - print(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}] [{self.CYAN}{level}{self.PINK}] -> [{self.CYAN}{message}{self.PINK}]{timer}") + timer = f" {self.MAGENTA_BRIGHT}In{self.WHITE} -> {self.MAGENTA_BRIGHT}{str(end - start)[:5]} Seconds {Fore.RESET}" if start and end else "" + print(f"{self.prefix}[{self.MAGENTA_BRIGHT}{time}{self.PINK}] [{self.CYAN}{level}{self.PINK}] -> [{self.CYAN}{message}{self.PINK}]{timer}") def message2(self, level: str, message: str, start: int = None, end: int = None) -> None: time = self.get_time() if start is not None and end is not None: - print(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}] {self.PINK}[{self.CYAN}{level}{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET} [{Fore.CYAN}{end - start}s{Style.RESET_ALL}]", end="\r") + print(f"{self.prefix}[{self.MAGENTA_BRIGHT}{time}{self.PINK}] {self.PINK}[{self.CYAN}{level}{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET} [{Fore.CYAN}{end - start}s{Style.RESET_ALL}]", end="\r") else: - print(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}] {self.PINK}[{Fore.BLUE}{level}{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET}", end="\r") + print(f"{self.prefix}[{self.MAGENTA_BRIGHT}{time}{self.PINK}] {self.PINK}[{Fore.BLUE}{level}{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET}", end="\r") - def question(self, message: str, start: int = None, end: int = None) -> None: + def message3(self, level: str, message: str, start: int = None, end: int = None) -> str: time = self.get_time() - i = input(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}]{Fore.RESET} {self.PINK}[{Fore.BLUE}?{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET}") - return i + return f"{self.prefix}[{self.MAGENTA_BRIGHT}{time}{self.PINK}] {self.PINK}[{self.CYAN}{level}{self.PINK}] -> {self.CYAN}{message}{Fore.RESET}" - def info(self, message: str, start: int = None, end: int = None) -> None: + def question(self, message: str, start: int = None, end: int = None) -> str: time = self.get_time() - print(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}]{Fore.RESET} {self.PINK}[{Fore.BLUE}!{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET}") - - def debug(self, message: str, start: int = None, end: int = None) -> None: - time = self.get_time() - print(f"{self.prefix}[{self.MAGENTAA}{time}{self.PINK}]{Fore.RESET} {self.PINK}[{Fore.YELLOW}DEBUG{self.PINK}] -> {Fore.RESET} {self.GREEN}{message}{Fore.RESET}") + i = input(f"{self.prefix}[{self.MAGENTA_BRIGHT}{time}{self.PINK}]{Fore.RESET} {self.PINK}[{Fore.BLUE}?{self.PINK}] -> {Fore.RESET} {self.CYAN}{message}{Fore.RESET}") + return i log = Logger() class Loader: - def __init__(self, prefix: str = "discord.cyberious.xyz", desc="Loading...", end="\r", timeout=0.1): + """Animated loading indicator with customizable appearance.""" + + SPINNER_CHARS = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"] + + def __init__( + self, + prefix: Optional[str] = "discord.cyberious.xyz", + desc: str = "Loading...", + end: str = "\r", + timeout: float = 0.1 + ) -> None: self.desc = desc self.end = end self.prefix = prefix self.timeout = timeout self.time = datetime.datetime.now().strftime("%H:%M:%S") - + self._thread = Thread(target=self._animate, daemon=True) - self.steps = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"] self.done = False def __enter__(self): @@ -88,21 +248,33 @@ def start(self): return self def _animate(self): - for c in cycle(self.steps): + for c in cycle(self.SPINNER_CHARS): if self.done: break - print(f"\r{log.PINK}[{log.MAGENTA}{self.prefix}{log.PINK}] [{log.MAGENTAA}{self.time}{log.PINK}] [{log.GREEN}{self.desc}{log.PINK}]{Fore.RESET} {c}", flush=True, end="") + prefix_str = f"[{log.MAGENTA}{self.prefix}{log.PINK}] " if self.prefix is not None else "" + print(f"\r{log.PINK}{prefix_str}[{log.MAGENTA_BRIGHT}{self.time}{log.PINK}] [{log.GREEN}{self.desc}{log.PINK}]{Fore.RESET} {c}", flush=True, end="") time.sleep(self.timeout) def stop(self): self.done = True if self.end != "\r": - print(f"\n{log.PINK}[{log.MAGENTA}{self.prefix}{log.PINK}] [{log.MAGENTAA}{self.time}{log.PINK}] {log.GREEN} {self.end} {Fore.RESET}", flush=True) + prefix_str = f"[{log.MAGENTA}{self.prefix}{log.PINK}] " if self.prefix is not None else "" + print(f"\n{log.PINK}{prefix_str}[{log.MAGENTA_BRIGHT}{self.time}{log.PINK}] {log.GREEN} {self.end} {Fore.RESET}", flush=True) else: print(self.end, flush=True) class Home: - def __init__(self, text, align="left", adinfo1=None, adinfo2=None, credits=None, clear=True): + """ASCII art text display with customizable formatting and layout.""" + + def __init__( + self, + text: str, + align: str = "left", + adinfo1: Optional[str] = None, + adinfo2: Optional[str] = None, + credits: Optional[str] = None, + clear: bool = True + ) -> None: self.text = text self.align = align self.adinfo1 = adinfo1 @@ -186,8 +358,6 @@ def _construct_adinfo_text(self, ascii_art_width): remaining_space = ascii_art_width - total_adinfo_length if remaining_space > 0: padding_between = ' ' * (remaining_space // 3) - return self.adinfo1 + padding_between + self.adinfo2 - else: return self.adinfo1 + ' ' + self.adinfo2 return self.adinfo1 or self.adinfo2 or '' diff --git a/setup.py b/setup.py index 2500dad..24d9ca4 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="logmagix", - version="1.10.3.1", + version="2.0.0", packages=find_packages(), install_requires=["colorama"], author="Sexfrance", diff --git a/test.py b/test.py index 517da22..e79795f 100644 --- a/test.py +++ b/test.py @@ -1,40 +1,91 @@ -from logmagix.logger import Logger, Loader, Home -# from logmagix import Logger, Loader +from logmagix.logger import Logger, Loader, Home, LogLevel import time -import uuid -log = Logger(prefix=None) -start_time = time.time() +# Initialize logger with custom prefix and optional file logging +logger = Logger( + prefix="TestLogger", + log_file="test.log", + max_file_size=1_000_000, + backup_count=3 +) -# Log messages -log.success("Everything is running smoothly!") -log.warning("Watch out, something might happen!") -log.failure("Critical error occurred!") -log.info("System is working properly") -log.debug(f"The system uuid is {uuid.getnode()}") -log.message("Dad", f"How are you? I'm gonna come soon!", start=start_time, end=time.time()) -log.question("How old are you? ") +# Test ASCII art banner +home = Home( + text="LOGMAGIX", + align="center", + adinfo1="Test Suite", + adinfo2="v1.0.0", + credits="Testing Framework", + clear=True +) +home.display() +# Test loader animation +with Loader(prefix="TestLoader", desc="Initializing tests...", timeout=0.1): + time.sleep(2) -# Use loader with custom prefix and context manager -with Loader(prefix="custom/loader/prefix", desc="Processing data..."): - time.sleep(2) # Simulate task +# Test all log levels +logger.info("Starting test suite") +logger.debug("Debug information") +logger.warning("Warning message") +logger.success("Success message") +logger.failure("Failure message") -# Use loader with custom prefix and start/stop methods -loader = Loader(prefix="custom/loader/prefix", desc="Saving files...", end="Done !", timeout=0.05).start() -time.sleep(2) # Simulate task -loader.stop() +# Test log level filtering +logger.info("Testing log level filtering...") +logger.set_min_level(LogLevel.WARNING) # Only show WARNING and above +logger.debug("This debug message should not appear") +logger.info("This info message should not appear") +logger.warning("This warning message should appear") +logger.success("This success message should appear") +logger.failure("This error message should appear") +# Reset log level +logger.set_min_level(LogLevel.DEBUG) -home_screen = Home( - text="LogMagix", - align="center", - adinfo1="discord.cyberious.xyz", - adinfo2="v1.0", - credits="Developed by sexfrance" -) +# Test batch logging +logger.info("Testing batch logging...") +logger.batch() +for i in range(2): + logger.info(f"Batch message {i+1}") + logger.success(f"Batch success {i+1}") + logger.warning(f"Batch warning {i+1}") + logger.failure(f"Batch failure {i+1}") + time.sleep(0.5) +logger.flush() -home_screen.display() +# Test message format with precise timing +logger.message("FORMAT1", "Testing message format 1") +start = time.time() +time.sleep(0.456) +end = time.time() +logger.message("FORMAT2", "Testing message format 2", start=start, end=end) + +# Test user input +answer = logger.question("Would you like to test critical exit? (y/n)") +if answer.lower() == 'y': + logger.critical("Critical exit test", exit_code=1) + +# Test loader with different end messages +with Loader(prefix="TestLoader", desc="Processing", end="Process completed!", timeout=0.05): + time.sleep(1) + +with Loader(prefix="TestLoader", desc="Analyzing", end="Analysis done!", timeout=0.15): + time.sleep(1) + +# Test Home with different alignments +home = Home( + text="TEST", + align="right", + adinfo1="Right Aligned", + adinfo2="Test", + credits="Alignment Test", + clear=False +) +home.display() +# Final loader with completion message +with Loader(prefix="TestLoader", desc="Finalizing", end="Tests completed!"): + time.sleep(2) -log.success("Processing completed!") \ No newline at end of file +logger.success("All tests completed successfully!") \ No newline at end of file