From 796a8a82f65878ad388514769d6a1957d6a3114d Mon Sep 17 00:00:00 2001 From: Nanaloveyuki Date: Tue, 29 Jul 2025 14:17:22 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20=E6=94=B9=E8=BF=9B=E4=BA=86?= =?UTF-8?q?=E5=AF=B9=E5=8D=A0=E4=BD=8D=E7=AC=A6=E5=92=8C=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logger_config.json | 2 +- src/logiliteal/levels/levels.py | 80 +++++++----- src/logiliteal/utils/configs.py | 38 +++++- src/logiliteal/utils/fmt.py | 193 ++++++++-------------------- src/logiliteal/utils/placeholder.py | 62 +++++++++ src/logiliteal/utils/regex.py | 128 ++++++++++++++++++ tests/logger_config.json | 32 ----- tests/t-level.py | 2 +- 8 files changed, 331 insertions(+), 206 deletions(-) create mode 100644 src/logiliteal/utils/placeholder.py create mode 100644 src/logiliteal/utils/regex.py delete mode 100644 tests/logger_config.json diff --git a/logger_config.json b/logger_config.json index e58ae4c..283a3b0 100644 --- a/logger_config.json +++ b/logger_config.json @@ -7,7 +7,7 @@ "enable_console": true, "enable_file": true, "console_color": true, - "console_level": "INFO", + "console_level": "DEBUG", "console_format": "{time} {levelname} | {prefix}{message}", "console_prefix": "Auto", "console_encoding": "utf-8", diff --git a/src/logiliteal/levels/levels.py b/src/logiliteal/levels/levels.py index 6271d4d..4bd9942 100644 --- a/src/logiliteal/levels/levels.py +++ b/src/logiliteal/levels/levels.py @@ -11,96 +11,116 @@ from ..utils.fmt import fmt_file, fmt_message, fmt_console from ..utils.configs import get_config, set_config from ..utils.time import get_asctime import pathlib +from pathlib import Path def _get_full_path(file_path, file_name): file_path.mkdir(parents=True, exist_ok=True) return file_path / file_name -file_path = pathlib.Path(get_config("file_path")) -file_name = get_config("file_name") -file_format = get_config("file_format") -file_encoding = get_config("file_encoding") -is_enable_console = get_config("enable_console") -is_enable_file = get_config("enable_file") - class Logger: def __init__(self): - if pathlib.Path(file_path).exists(): - if not pathlib.Path(file_path).is_dir(): - self.warn("日志文件路径不是目录,已自动自动使用默认目录") + project_root = Path(__file__).parent.parent.parent.parent + file_path = project_root / get_config("file_path") + file_path.mkdir(parents=True, exist_ok=True) + if file_path.exists(): + if not file_path.is_dir(): + self.warn("日志文件路径不是目录,已自动使用默认目录") set_config("file_path", "./logs") pathlib.Path("./logs").mkdir(parents=True, exist_ok=True) - if _get_full_path(file_path, file_name).exists(): + current_file = _get_full_path(file_path, get_config("file_name")) + if current_file.exists(): from os import rename - rename(_get_full_path(file_path, file_name), _get_full_path(file_path, f"{get_asctime().replace(':', '-')}.log")) + rename(current_file, _get_full_path(file_path, f"{get_asctime().replace(':', '-')}.log")) self.debug("日志文件已存在,已自动重命名") - - def _log(self, msg, pf, lvn): - if is_enable_file: - with open(_get_full_path(file_path, file_name), "a", encoding=file_encoding) as f: - f.write(fmt_file(lvn, fmt_message(msg, no_placeholder=True), pf)) - if is_enable_console: + + def _log(self, msg, pf, lvn, no_file: bool = False, no_console: bool = False): + project_root = Path(__file__).parent.parent.parent.parent + file_path = project_root / get_config("file_path") + file_path.mkdir(parents=True, exist_ok=True) + file_name = get_config("file_name") + file_encoding = get_config("file_encoding") + is_enable_file = get_config("enable_file") + is_enable_console = get_config("enable_console") + if not no_file and is_enable_file: + try: + with open(_get_full_path(file_path, file_name), "a", encoding=file_encoding) as f: + f.write(fmt_file(lvn, fmt_message(msg, no_placeholder=True, no_process=True), pf)) + except Exception as e: + self.error(f"日志写入失败: {str(e)}", no_file=True) + if not no_console and is_enable_console: console_output = fmt_console(lvn, fmt_message(msg, no_placeholder=True), pf) if console_output is not None: print(console_output) return fmt_console(lvn, fmt_message(msg, no_placeholder=True), pf) - def debug(self, message: Any, prefix: str | None = None, level: int = 0) -> Optional[str]: + def debug(self, message: Any, prefix: str | None = None, level: int = 0, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 调试日志 Debug log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(0~9) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) + return self._log(message, prefix, level, no_file, no_console) - def info(self, message: Any, prefix: str | None = None, level: int = 10) -> Optional[str]: + def info(self, message: Any, prefix: str | None = None, level: int = 10, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 信息日志 Info log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(10~19) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) + return self._log(message, prefix, level, no_file, no_console) - def warn(self, message: Any, prefix: str | None = None, level: int = 20) -> Optional[str]: + def warn(self, message: Any, prefix: str | None = None, level: int = 20, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 警告日志 Warn log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(20~29) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) + return self._log(message, prefix, level, no_file, no_console) - def error(self, message: Any, prefix: str | None = None, level: int = 30) -> Optional[str]: + def error(self, message: Any, prefix: str | None = None, level: int = 30, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 错误日志 Error log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(30~39) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) + return self._log(message, prefix, level, no_file, no_console) - def critical(self, message: Any, prefix: str | None = None, level: int = 40) -> Optional[str]: + def critical(self, message: Any, prefix: str | None = None, level: int = 40, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 严重错误日志 Critical error log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(40~49) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) + return self._log(message, prefix, level, no_file, no_console) - def log(self, message: Any, prefix: str | None = None, level: int = 50) -> Optional[str]: + def log(self, message: Any, prefix: str | None = None, level: int = 50, no_file: bool = False, no_console: bool = False) -> Optional[str]: """ 自定义日志 Custom log :param message: 消息内容 Message content :param prefix: 前缀 Prefix :param level: 日志级别 Log level(50~59...) + :param no_file: 不写入文件 Do not write to file + :param no_console: 不输出到控制台 Do not output to console """ - return self._log(message, prefix, level) \ No newline at end of file + return self._log(message, prefix, level, no_file, no_console) diff --git a/src/logiliteal/utils/configs.py b/src/logiliteal/utils/configs.py index d236326..ed4e4b4 100644 --- a/src/logiliteal/utils/configs.py +++ b/src/logiliteal/utils/configs.py @@ -9,11 +9,43 @@ py-logiliteal's config settings, used to set py-logiliteal's global config import json from os import remove import shutil +import os from pathlib import Path from typing import Union, Optional, Tuple from logging import error -DEFAULT_CONFIG_PATH = "logger_config.json" +def get_config_path(): + # 检查环境变量 + env_config = os.getenv('LOGILITEAL_CONFIG') + if env_config and os.path.exists(env_config): + return env_config + + # 检查当前工作目录 + cwd_config = os.path.join(os.getcwd(), 'logger_config.json') + if os.path.exists(cwd_config): + return cwd_config + + # 检查XDG配置目录 + xdg_config_dir = os.getenv('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')) + xdg_config_path = os.path.join(xdg_config_dir, 'logiliteal', 'logger_config.json') + + # 创建目录(如果不存在) + if not os.path.exists(os.path.dirname(xdg_config_path)): + try: + os.makedirs(os.path.dirname(xdg_config_path), exist_ok=True) + except Exception as e: + error(f"创建配置目录失败: {e}") + # 回退到项目根目录的配置文件 + project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + fallback_config = os.path.join(project_root, 'logger_config.json') + if os.path.exists(fallback_config): + return fallback_config + else: + return xdg_config_path + + return xdg_config_path + +DEFAULT_CONFIG_PATH = get_config_path() DEFAULT_CONFIG = { "file_level": "DEBUG", "file_name": "latest.log", @@ -23,7 +55,7 @@ DEFAULT_CONFIG = { "enable_console": True, "enable_file": True, "console_color": True, - "console_level": "INFO", + "console_level": "DEBUG", "console_format": "{time} {levelname} | {prefix}{message}", "console_prefix": "Auto", "console_encoding": "utf-8", @@ -94,6 +126,8 @@ def get_config(select: str = None) -> Union[dict, str, bool, int, None]: g_config_cache = json.load(f) g_config_mtime = current_mtime else: + # 确保目录存在 + config_path.parent.mkdir(parents=True, exist_ok=True) with open(config_path, "w", encoding="utf-8") as f: json.dump(DEFAULT_CONFIG, f, indent=4) g_config_cache = DEFAULT_CONFIG diff --git a/src/logiliteal/utils/fmt.py b/src/logiliteal/utils/fmt.py index 83bb91c..3c895a8 100644 --- a/src/logiliteal/utils/fmt.py +++ b/src/logiliteal/utils/fmt.py @@ -10,7 +10,15 @@ from .configs import get_config from typing import Any, Optional from .time import get_asctime, get_time, get_weekday, get_date from .styles import set_color, set_bg_color -import re +from .regex import ( + process_links, + process_markdown_formats, + process_html_styles, + process_special_tags, + process_color_formatting +) +from .placeholder import process_placeholder, SafeDict + if get_config("time_color") is None: time_color = "#28ffb6" @@ -61,29 +69,28 @@ def fmt_placeholder(message: Any, use_date_color: bool = True) -> str: :param message: 消息内容 Message content :return: 格式化后的消息 Formatted message """ - class SafeDict(dict): - def __missing__(self, key): - return f'{{{key}}}' - if not isinstance(message, str): message = str(message) - if use_date_color: - message = message.format_map(SafeDict( - asctime = set_color(get_asctime(),time_color), - time = set_color(get_time(),time_color), - weekday = set_color(get_weekday(),time_color), - date = set_color(get_date(),time_color) - )) - else: - message = message.format_map(SafeDict( - asctime = get_asctime(), - time = get_time(), - weekday = get_weekday(), - date = get_date(), - )) - return message -def fmt_message(message: Any, no_placeholder: bool = False, no_color: bool = False) -> str: + context = { + "asctime": set_color(get_asctime(), time_color) if use_date_color else get_asctime(), + "time": set_color(get_time(), time_color) if use_date_color else get_time(), + "weekday": set_color(get_weekday(), time_color) if use_date_color else get_weekday(), + "date": set_color(get_date(), time_color) if use_date_color else get_date(), + } + + return process_placeholder(message, context) + +def fmt_message( + message: Any, + no_placeholder: bool = False, + no_style: bool = False, + no_process: bool = False, + no_tags: bool = False, + no_links: bool = False, + no_markdown: bool = False, + no_html: bool = False, + ) -> str: """ 格式化消息内容 Format message content @@ -91,26 +98,29 @@ def fmt_message(message: Any, no_placeholder: bool = False, no_color: bool = Fal :return: 格式化后的消息 Formatted message """ - def process_color_tags(msg: str) -> str: - # 优化处理顺序,确保链接和基础格式优先处理 - processed = _process_color_formatting( - _process_special_tags( - _process_html_styles( - _process_markdown_formats( - _process_links(msg) - ) - ) - ) + def process_color_tags(msg: str, no_process: bool = False) -> str: + processed = process_color_formatting( + process_special_tags( + process_html_styles( + process_markdown_formats( + process_links(msg, no_links), + no_markdown + ), + no_html + ), + no_tags + ), + no_process ) return processed - if no_color: - processed_message = str(message) - else: - processed_message = process_color_tags(str(message)) - if no_placeholder: - return processed_message - else: - return process_color_tags(fmt_placeholder(processed_message)) if not no_color else fmt_placeholder(processed_message) + processed_message = str(message) + if not no_placeholder: + processed_message = fmt_placeholder(processed_message) + if not no_style: + processed_message = process_color_tags(processed_message) + if no_process: + return message + return processed_message def fmt_level_name(level_name: str) -> str: if get_config("console_color") != True: @@ -137,7 +147,7 @@ def fmt_console(level: int, message: Any, prefix: str | None = None) -> Optional :return: 格式化后的消息 Formatted message """ console_level = get_config("console_level") - if level != -1 and fmt_level(console_level) > level: + if level != -1 and level < fmt_level(console_level): return None fmt = get_config("console_format") prefix = prefix or "" @@ -157,111 +167,14 @@ def fmt_file(level: int, message: Any, prefix: str | None = None) -> Optional[st """ fl = get_config("file_level") fmt = get_config("file_format") - if fmt_level(fl) > level: + if level != -1 and level < fmt_level(fl): return None if prefix is None: prefix = "" fmt = fmt_placeholder(fmt, use_date_color=False) return f"{fmt.format( levelname = fmt_level_number(level), - prefix = fmt_message(prefix, no_placeholder=True, no_color=True), - message = fmt_message(message, no_placeholder=True, no_color=True) + prefix = fmt_message(prefix, no_placeholder=True, no_style=True), + message = fmt_message(message, no_placeholder=True, no_style=True) )}\n" -def _process_links(text: str) -> str: - from collections import deque - - link_stack = deque() - placeholder_count = 0 - placeholders = {} - - def replace_link(m): - nonlocal placeholder_count - placeholder_count += 1 - if len(m.groups()) == 2 and m.group(2) and not m.group(1).startswith('http'): - # Markdown链接 [text](url) - url = m.group(2).strip() - text = m.group(1) - else: - url = m.group(1) - text = m.group(2) - placeholder = f"__LINK_PLACEHOLDER_{placeholder_count}__" - placeholders[placeholder] = (url if url else "#", text) - link_stack.append(placeholder) - return placeholder - - text = re.sub(r'(.*?)', replace_link, text, flags=re.DOTALL) - text = re.sub(r'(.*?)', replace_link, text, flags=re.DOTALL) - text = re.sub(r'\[(.*?)\]\((.*?)\)', replace_link, text) - - for placeholder, (url, text_content) in placeholders.items(): - ansi_link = f'\033]8;;{url}\033\\{set_color("\033[4m" + text_content, "#5f93ff")}\033]8;;\033\\' - text = text.replace(placeholder, ansi_link) - - return text - -def _process_markdown_formats(text: str) -> str: - # Markdown粗体 (**text**) - text = re.sub(r'\*\*(.*?)\*\*', '\033[1m\\g<1>\033[22m', text) - # Markdown斜体 (*text*) - text = re.sub(r'\*(.*?)\*', '\033[3m\\g<1>\033[23m', text) - # Markdown下划线 (__text__) - text = re.sub(r'__(.*?)__', '\033[4m\\g<1>\033[24m', text) - # Markdown删除线 (~~text~~) - text = re.sub(r'~~(.*?)~~', '\033[9m\\g<1>\033[29m', text) - return text - -def _process_html_styles(text: str) -> str: - text = re.sub(r'([^<]*?)(|$)', - lambda m: '\033[3m' + m.group(1) + '\033[23m', text, flags=re.DOTALL) - text = re.sub(r'([^<]*?)', - lambda m: '\033[1m' + m.group(1) + '\033[22m', text) - text = re.sub(r'([^<]*?)', - lambda m: '\033[4m' + m.group(1) + '\033[24m', text) - text = re.sub(r'([^<]*?)(|$)', - lambda m: '\033[9m' + m.group(1) + '\033[29m', text, flags=re.DOTALL) - return text - -def _process_special_tags(text: str) -> str: - text = re.sub(r'
', '\n', text) - text = re.sub(r'', '\033[0m', text) - text = re.sub(r'

(.*?)

', r'\n\033[0m\g<1>\033[0m\n', text, flags=re.DOTALL) - text = re.sub(r'

(.*?)(

|$)', r'\n\033[0m\g<1>\033[0m\n', text, flags=re.DOTALL) - text = re.sub(r'

', '\033[0m\n', text) - return text - -def _process_color_formatting(text: str) -> str: - import re - - color_pattern = r'<#([0-9a-fA-F]{6})>' - close_pattern = r'' - - parts = re.split(f'({color_pattern}|{close_pattern})', text) - result = [] - color_stack = [] - - for part in parts: - if part and re.fullmatch(color_pattern, part): - color = re.match(color_pattern, part).group(1) - color_stack.append(color) - continue - elif part == '': - if color_stack: - color_stack.pop() - continue - elif part: - if color_stack: - current_color = color_stack[-1] - r = int(current_color[0:2], 16) - g = int(current_color[2:4], 16) - b = int(current_color[4:6], 16) - ansi_code = f'\033[38;2;{r};{g};{b}m' - reset_code = '\033[0m' - result.append(f'{ansi_code}{part}{reset_code}') - else: - result.append(part) - - processed_text = ''.join(result) - processed_text = re.sub(f'{color_pattern}|{close_pattern}|[0-9a-fA-F]{{6}}', '', processed_text) - - return processed_text diff --git a/src/logiliteal/utils/placeholder.py b/src/logiliteal/utils/placeholder.py new file mode 100644 index 0000000..cf085a2 --- /dev/null +++ b/src/logiliteal/utils/placeholder.py @@ -0,0 +1,62 @@ +""" +占位符处理工具 +""" +from typing import Dict, Any, Optional +import re + + +class SafeDict(Dict[str, Any]): + """安全的字典类,用于处理缺失键的占位符替换""" + def __missing__(self, key: str) -> str: + return f"{{{key}}}" + + +def process_placeholder(text: str, context: Optional[Dict[str, Any]] = None) -> str: + """处理文本中的占位符替换 + + Args: + text: 包含占位符的原始文本 + context: 用于替换占位符的上下文字典 + + Returns: + 替换后的文本 + """ + if not context: + return text + + # 处理简单占位符 {key} + safe_context = SafeDict(**context) + text = text.format_map(safe_context) + + # 处理条件占位符 {{if condition}}content{{endif}} + def replace_condition(match): + condition = match.group(1).strip() + content = match.group(2).strip() + # 简单条件解析(仅支持key存在性检查) + if condition.startswith('!'): + key = condition[1:].strip() + return '' if key in context else content + return content if condition in context else '' + + text = re.sub(r'\{\{if\s+(.*?)\}\}([\s\S]*?)\{\{endif\}\}', replace_condition, text, flags=re.IGNORECASE) + + # 处理循环占位符 {{for item in list}}content{{endfor}} + def replace_loop(match): + items = match.group(1).strip().split(' in ') + if len(items) != 2: + return match.group(0) + item_name, list_name = items + content = match.group(2).strip() + + if list_name not in context or not isinstance(context[list_name], list): + return '' + + result = [] + for item in context[list_name]: + item_context = {item_name: item} + result.append(process_placeholder(content, item_context)) + return ''.join(result) + + text = re.sub(r'\{\{for\s+(.*?)\}\}([\s\S]*?)\{\{endfor\}\}', replace_loop, text, flags=re.IGNORECASE) + + return text \ No newline at end of file diff --git a/src/logiliteal/utils/regex.py b/src/logiliteal/utils/regex.py new file mode 100644 index 0000000..fce2653 --- /dev/null +++ b/src/logiliteal/utils/regex.py @@ -0,0 +1,128 @@ +""" +正则表达式处理工具 +""" +import re +from collections import deque +from .styles import set_color, set_bg_color + + +def process_links(text: str, no_process: bool = False) -> str: + """处理链接标签(HTML和Markdown格式)""" + if no_process: + return text + link_stack = deque() + placeholder_count = 0 + placeholders = {} + + def replace_link(m): + nonlocal placeholder_count + placeholder_count += 1 + if len(m.groups()) == 2 and m.group(2) and not m.group(1).startswith('http'): + # Markdown链接 [text](url) + url = m.group(2).strip() + text = m.group(1) + else: + url = m.group(1) + text = m.group(2) + placeholder = f"__LINK_PLACEHOLDER_{placeholder_count}__" + placeholders[placeholder] = (url if url else "#", text) + link_stack.append(placeholder) + return placeholder + + text = re.sub(r'(.*?)', replace_link, text, flags=re.DOTALL) + text = re.sub(r'(.*?)', replace_link, text, flags=re.DOTALL) + text = re.sub(r'\[(.*?)\]\((.*?)\)', replace_link, text) + + for placeholder, (url, text_content) in placeholders.items(): + ansi_link = f'\033]8;;{url}\033\\{set_color("\033[4m" + text_content, "#5f93ff")}\033]8;;\033\\' + text = text.replace(placeholder, ansi_link) + + return text + + +def process_markdown_formats(text: str, no_process: bool = False) -> str: + """处理Markdown格式""" + if no_process: + return text + # Markdown粗体 (**text**) + text = re.sub(r'\*\*(.*?)\*\*', '\033[1m\\g<1>\033[22m', text) + # Markdown斜体 (*text*) + text = re.sub(r'\*(.*?)\*', '\033[3m\\g<1>\033[23m', text) + # Markdown下划线 (__text__) + text = re.sub(r'__(.*?)__', '\033[4m\\g<1>\033[24m', text) + # Markdown删除线 (~~text~~) + text = re.sub(r'~~(.*?)~~', '\033[9m\\g<1>\033[29m', text) + return text + + +def process_html_styles(text: str, no_process: bool = False) -> str: + """处理HTML样式标签""" + if no_process: + return text + # HTML斜体 + text = re.sub(r'([^<]*?)(|$)', + lambda m: '\033[3m' + m.group(1) + '\033[23m', text, flags=re.DOTALL) + # HTML粗体 + text = re.sub(r'([^<]*?)', + lambda m: '\033[1m' + m.group(1) + '\033[22m', text) + # HTML下划线 + text = re.sub(r'([^<]*?)', + lambda m: '\033[4m' + m.group(1) + '\033[24m', text) + # HTML删除线 + text = re.sub(r'([^<]*?)(|$)', + lambda m: '\033[9m' + m.group(1) + '\033[29m', text, flags=re.DOTALL) + return text + + +def process_special_tags(text: str, no_process: bool = False) -> str: + """处理特殊标签(换行、重置、段落)""" + if no_process: + return text + text = re.sub(r'
', '\n', text) + text = re.sub(r'', '\033[0m', text) + # 处理段落标签 + text = re.sub(r'

(.*?)

', r'\n\033[0m\\g<1>\033[0m\n', text, flags=re.DOTALL) + text = re.sub(r'

(.*?)(

|$)', r'\n\033[0m\\g<1>\033[0m\n', text, flags=re.DOTALL) + text = re.sub(r'

', '\033[0m\n', text) + return text + + +def process_color_formatting(text: str, no_process: bool = False) -> str: + """处理颜色标签""" + if no_process: + return text + color_pattern = r'<#([0-9a-fA-F]{6})>' + close_pattern = r'' + + parts = re.split(f'({color_pattern}|{close_pattern})', text) + result = [] + color_stack = [] + + for part in parts: + if part and re.fullmatch(color_pattern, part): + color = re.match(color_pattern, part).group(1) + color_stack.append(color) + continue + elif part == '': + if color_stack: + color_stack.pop() + continue + elif part: + if color_stack: + current_color = color_stack[-1] + r = int(current_color[0:2], 16) + g = int(current_color[2:4], 16) + b = int(current_color[4:6], 16) + ansi_code = f'\033[38;2;{r};{g};{b}m' + reset_code = '\033[0m' + result.append(f'{ansi_code}{part}{reset_code}') + else: + processed_text = part + processed_text = re.sub(r'<#([0-9a-fA-F]{6})>', lambda m: f'<{set_color(f"#{m.group(1)}")}>', processed_text) + result.append(processed_text) + + processed_text = ''.join(result) + processed_text = re.sub(f'{color_pattern}|{close_pattern}', '', processed_text) + processed_text = re.sub(r'[0-9a-fA-F]{6}', '', processed_text) + + return processed_text \ No newline at end of file diff --git a/tests/logger_config.json b/tests/logger_config.json deleted file mode 100644 index 5194963..0000000 --- a/tests/logger_config.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "file_level": "DEBUG", - "file_name": "latest.log", - "file_path": "./logs", - "file_format": "{asctime} {levelname} | {prefix}{message}", - "file_encoding": "utf-8", - "enable_console": true, - "enable_file": true, - "console_color": true, - "console_level": "INFO", - "console_format": "{time} {levelname} | {prefix}{message}", - "console_prefix": "Auto", - "console_encoding": "utf-8", - "asctime_format": "%Y-%m-%d %H:%M:%S", - "time_format": "%H:%M:%S", - "date_format": "%Y-%m-%d", - "weekday_format": "%A", - "level_name": { - "DEBUG": "DEBUG", - "INFO": "INFO", - "WARN": "WARN", - "ERRO": "ERRO", - "CRIT": "CRIT" - }, - "level_color": { - "DEBUG": "#c1d5ff", - "INFO": "#c1ffff", - "WARN": "#fff600", - "ERRO": "#ffa000", - "CRIT": "#ff8181" - } -} \ No newline at end of file diff --git a/tests/t-level.py b/tests/t-level.py index 536513a..1131774 100644 --- a/tests/t-level.py +++ b/tests/t-level.py @@ -8,8 +8,8 @@ from src.logiliteal import Logger log = Logger() -log.info("测试信息日志") log.debug("测试调试日志") +log.info("测试信息日志") log.warn("测试警告日志") log.error("测试错误日志") log.critical("测试严重错误日志") \ No newline at end of file