添加了fmt格式化及其相关的timestyle基本组件

This commit is contained in:
Nanaloveyuki
2025-07-27 21:52:41 +08:00
parent 4d9c4aca5a
commit 7e53fc099e
3 changed files with 306 additions and 0 deletions

192
src/utils/fmt.py Normal file
View File

@ -0,0 +1,192 @@
"""
pliblog的格式化工具,用于格式化日志输出
pliblog's formatter, used to format log output
"""
# encoding = utf-8
# python 3.13.5
from .configs import get_config
from typing import Any, Optional, Union
from .time import get_asctime, get_time, get_weekday, get_date
from .styles import set_color, set_bg_color
import re
def fmt_level(level: str) -> int:
"""
格式化日志级别
Format log level
:param level: 日志级别 Log level
:return: 格式化后的日志级别 Formatted log level
"""
level_map = {
"DEBUG": 10,
"INFO": 20,
"WARN": 30,
"ERRO": 40,
"CRIT": 50,
}
if level == "UNKN":
return -1
return level_map.get(level.upper(), 0)
def fmt_level_number(level: int) -> str:
"""
格式化日志级别数字
Format log level number
:param level: 日志级别数字 Log level number
:return: 格式化后的日志级别 Formatted log level
"""
if level <= 10 and level >= 0:
return "DEBUG"
elif level <= 20 and level > 10:
return "INFO"
elif level <= 30 and level > 20:
return "WARN"
elif level <= 40 and level > 30:
return "ERRO"
elif level <= 50 and level > 40:
return "CRIT"
else:
return "UNKN"
def fmt_placeholder(message: Any, use_date_color: bool = True) -> str:
"""
格式化占位符
Format placeholder
: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(),"#28ffb6"),
time = set_color(get_time(),"#28ffb6"),
weekday = set_color(get_weekday(),"#28ffb6"),
date = set_color(get_date(),"#28ffb6")
))
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) -> str:
"""
格式化消息内容
Format message content
:param message: 消息内容 Message content
:return: 格式化后的消息 Formatted message
"""
def process_color_tags(msg: str) -> str:
stack = []
result = []
current_content = []
last_end = 0
pattern = re.compile(r'(<#([0-9a-fA-F]{6})>|</>)')
for match in pattern.finditer(msg):
text_between = msg[last_end:match.start()]
if stack:
current_content.append(text_between)
else:
result.append(text_between)
last_end = match.end()
tag = match.group(1)
if tag.startswith('<#'):
color_code = match.group(2)
stack.append(color_code)
else:
if stack:
color = stack.pop()
colored_content = set_color(''.join(current_content), f'#{color}')
result.append(colored_content)
current_content = []
else:
result.append(tag)
remaining_text = msg[last_end:]
if stack:
current_content.append(remaining_text)
else:
result.append(remaining_text)
for color in reversed(stack):
result.append(f'<#{color}>')
result.append(''.join(current_content))
current_content = []
return ''.join(result)
if no_placeholder:
return process_color_tags(str(message))
else:
return process_color_tags(fmt_placeholder(str(message)))
def fmt_level_name(level_name: str) -> str:
if get_config("console_color") != True:
return level_name
level_name_nick_map = get_config("level_name")
if level_name in level_name_nick_map:
_lnn = level_name_nick_map[level_name]
level_color_map = get_config("level_color")
if level_name in level_color_map:
if level_name == "DEBUG":
return set_bg_color(set_color(_lnn, level_color_map[level_name]), "#34495e")
return set_color(_lnn, level_color_map[level_name])
return set_color(_lnn)
return "UNKN"
def fmt_console(level: int, message: Any, prefix: str | None = None) -> Optional[str]:
"""
格式化控制台输出
Format console output
:param level: 日志级别 Log level
:param message: 消息内容 Message content
:return: 格式化后的消息 Formatted message
"""
cl = get_config("console_level")
fmt = get_config("console_format")
if fmt_level(cl) > level:
return None
if prefix is None:
prefix = ""
fmt = fmt_placeholder(fmt)
return fmt.format(
levelname = fmt_level_name(fmt_level_number(level)),
prefix = prefix,
message = fmt_message(message, no_placeholder=True)
)
def fmt_file(level: int, message: Any, prefix: str | None = None) -> Optional[str]:
"""
格式化文件输出
Format file output
:param level: 日志级别 Log level
:param message: 消息内容 Message content
:return: 格式化后的消息 Formatted message
"""
fl = get_config("file_level")
fmt = get_config("file_format")
if fmt_level(fl) > level:
return None
if prefix is None:
prefix = ""
fmt = fmt_placeholder(fmt)
return fmt.format(
levelname = fmt_level_name(fmt_level_number(level)),
prefix = prefix,
message = fmt_message(message, no_placeholder=True)
)

50
src/utils/styles.py Normal file
View File

@ -0,0 +1,50 @@
"""
pliblog的样式工具,用于格式化日志输出
pliblog's style tools, used to format log output
"""
# encoding = utf-8
# python 3.13.5
from .configs import get_config
from typing import Union, Optional
def _get_hex_to_ansi(hex_color: str) -> Union[Optional[str], None]:
"""
将16进制颜色值转换为ANSI转义序列
Convert hex color value to ANSI escape sequence
:param hex_color: 16进制颜色值 Hex color value
:return: ANSI转义序列 ANSI escape sequence
"""
if not hex_color.startswith("#"):
return None
r, g, b = int(hex_color[1:3], 16), int(hex_color[3:5], 16), int(hex_color[5:7], 16)
return f"\033[38;2;{r};{g};{b}m"
def set_color(text: str, color: str) -> str:
"""
设置文本颜色
Set text color
:param text: 文本内容 Text content
:param color: 颜色值 Color value
:return: 格式化后的文本 Formatted text
"""
ansi = _get_hex_to_ansi(color)
if not ansi:
return text
return f"{ansi}{text}\033[0m"
def set_bg_color(text: str, color: str) -> str:
"""
设置文本背景颜色
Set text background color
:param text: 文本内容 Text content
:param color: 颜色值 Color value
:return: 格式化后的文本 Formatted text
"""
ansi = _get_hex_to_ansi(color)
if not ansi:
return text
# 将前景色ANSI代码转换为背景色代码 (38→48)
ansi = ansi.replace("38;", "48;")
return f"{ansi}{text}\033[0m"

64
src/utils/time.py Normal file
View File

@ -0,0 +1,64 @@
"""
时间工具模块,用于时间格式化和输出,缓存时间格式化结果
Time utility module, used for time formatting and output, caching time formatting results
"""
# encoding = utf-8
# python 3.13.5
from datetime import datetime
from .configs import get_config
cache_time: str = ""
cache_asctime: str = ""
cache_date: str = ""
cache_weekday: str = ""
def get_asctime() -> str:
"""
获取当前时间(YYYY-MM-DD HH:MM:SS),并缓存格式化结果
Get current time(YYYY-MM-DD HH:MM:SS) and cache formatted result
:return: 格式化后的时间 Formatted time
"""
global cache_asctime
if cache_asctime:
return cache_asctime
cache_asctime = datetime.now().strftime(get_config("date_format"))
return cache_asctime
def get_time() -> str:
"""
获取当前时间(HH:MM:SS),并缓存格式化结果
Get current time(HH:MM:SS) and cache formatted result
:return: 格式化后的时间 Formatted time
"""
global cache_time
if cache_time:
return cache_time
cache_time = datetime.now().strftime("%H:%M:%S")
return cache_time
def get_date() -> str:
"""
获取当前日期(YYYY-MM-DD),并缓存格式化结果
获取当前日期(星期几),并缓存格式化结果
Get current date(YYYY-MM-DD) and cache formatted result
:return: 格式化后的日期 Formatted date
"""
global cache_date
if cache_date:
return cache_date
cache_date = datetime.now().strftime("%Y-%m-%d")
return cache_date
def get_weekday() -> str:
"""
获取当前日期(星期几),并缓存格式化结果
Get current date(weekday) and cache formatted result
:return: 格式化后的星期几 Formatted weekday
"""
global cache_weekday
if cache_weekday:
return cache_weekday
cache_weekday = datetime.now().strftime("%A")
return cache_weekday