import json import logging import time import uuid from typing import Any from astrbot import logger from astrbot.core import LogManager, astrbot_config from astrbot.core.log import LogQueueHandler _cached_log_broker = None _trace_logger = None def _get_log_broker(): global _cached_log_broker if _cached_log_broker is not None: return _cached_log_broker for handler in logger.handlers: if isinstance(handler, LogQueueHandler): _cached_log_broker = handler.log_broker return _cached_log_broker return None def _get_trace_logger(): global _trace_logger if _trace_logger is not None: return _trace_logger # 按配置初始化 trace 文件日志 LogManager.configure_trace_logger(astrbot_config) _trace_logger = logging.getLogger("astrbot.trace") return _trace_logger class TraceSpan: def __init__( self, name: str, umo: str | None = None, sender_name: str | None = None, message_outline: str | None = None, ) -> None: self.span_id = str(uuid.uuid4()) self.name = name self.umo = umo self.sender_name = sender_name self.message_outline = message_outline self.started_at = time.time() def record(self, action: str, **fields: Any) -> None: # Check if trace recording is enabled if not astrbot_config.get("trace_enable", True): return payload = { "type": "trace", "level": "TRACE", "time": time.time(), "span_id": self.span_id, "name": self.name, "umo": self.umo, "sender_name": self.sender_name, "message_outline": self.message_outline, "action": action, "fields": fields, } log_broker = _get_log_broker() if log_broker: log_broker.publish(payload) else: logger.info(f"[trace] {payload}") trace_logger = _get_trace_logger() if trace_logger and trace_logger.handlers: trace_logger.info(json.dumps(payload, ensure_ascii=False))