feat(trace): 实现语义化 Trace ID 机制并美化报告展现

- [TraceContext] 重构 ID 生成算法,支持包含群名和时间(如 manual_技术交流群_1733),极大提升日志调试效率。
 - [视觉美化] 从用户可见消息(初始提示及图片 Caption)中彻底移除技术性的 [ID: xxx] 字符串。
 - [去重增强] 在报告 Caption 中引入基于秒级时间戳的“隐式指纹”,配合共享正则匹配,确保精准去重。
 - [自动分析] 优化自动调度器逻辑,引入群名缓存,使服务端定时任务日志更具业务可读性。
 - [逻辑精简] 利用插件现有的任务并发锁,移除了 Trace ID 中冗余的 4 位随机后缀,进一步精简长度。
This commit is contained in:
SXP-Simon
2026-03-12 18:03:23 +08:00
parent 16c756259a
commit bd991e9c16
5 changed files with 113 additions and 31 deletions
+47 -6
View File
@@ -6,12 +6,20 @@
import functools
import logging
import re
import uuid
from contextvars import ContextVar, Token
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Optional
# Trace ID 中群名的最大长度(平衡可读性和日志宽度)
_MAX_GROUP_NAME_LEN = 10
# 用于匹配报告 Caption 中去重 Token 的正则模式
# 格式: "| MM-DD HH:MM:SS"
REPORT_CAPTION_PATTERN = re.compile(r"\| (\d{2}-\d{2} \d{2}:\d{2}:\d{2})")
# 当前追踪的上下文变量
_current_trace: ContextVar[Optional["TraceContext"]] = ContextVar(
"current_trace", default=None
@@ -146,18 +154,51 @@ class TraceContext:
return new_ctx
@staticmethod
def generate(prefix: str = "") -> str:
def generate(prefix: str = "", group_name: str = "") -> str:
"""
[兼容性接口] 生成一个带前缀的唯一追踪 ID。
生成语义化、易读的追踪 ID。
格式: {来源}_{群名}_{时间点}
示例: manual_系统交流群_1733
由于插件存在任务锁 (DuplicateGroupTaskError),确保了一个群同一时间只有一个分析任务,
因此 时间点 (HHmm) 已足够提供唯一性,无需 UUID 缀。
Args:
prefix (str): 前缀,如 'manual_12345'
prefix (str): 来源标识,如 'manual', 'group', 'incr', 'report'
group_name (str): 可选群名,用于日志中快速识别
Returns:
str: 格式为 'prefix-uuid'字符串
str: 语义化 TraceID 字符串
"""
uid = str(uuid.uuid4())[:8]
return f"{prefix}-{uid}" if prefix else uid
timestamp = datetime.now().strftime("%H%M")
parts: list[str] = []
if prefix:
parts.append(prefix)
if group_name:
# 清理:移除空白符和文件系统不安全字符
safe_name = re.sub(r'[\s\n\r\t/\\:*?"<>|\[\]{}]', "", group_name)
safe_name = safe_name[:_MAX_GROUP_NAME_LEN]
if safe_name:
parts.append(safe_name)
parts.append(timestamp)
return "_".join(parts)
@staticmethod
def make_report_caption() -> str:
"""
生成整洁的、面向用户的报告 Caption,包含用于去重的隐式时间戳。
该时间戳用作图片去重检查的 Token。
格式: "📊 每日群聊分析报告已生成 | MM-DD HH:MM:SS"
Returns:
str: 报告 Caption 字符串
"""
ts = datetime.now().strftime("%m-%d %H:%M:%S")
return f"📊 每日群聊分析报告已生成 | {ts}"
@classmethod
def set(cls, trace_id: str) -> None: