Skip to content

feat: trace#4747

Merged
Soulter merged 3 commits intomasterfrom
feat/trace
Jan 30, 2026
Merged

feat: trace#4747
Soulter merged 3 commits intomasterfrom
feat/trace

Conversation

@Soulter
Copy link
Member

@Soulter Soulter commented Jan 29, 2026

Modifications / 改动点

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果


Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

为消息事件引入追踪 span 系统,并在仪表盘中提供实时追踪查看器,用于实时检查事件级别的追踪信息。

New Features:

  • 添加 TraceSpan 工具以及贯穿整个消息处理管线的事件级追踪钩子,用于记录结构化的追踪事件。
  • 在仪表盘中新增 Trace 页面,提供由日志历史和服务器发送事件(SSE)驱动的实时追踪查看器,并包含导航条目和 i18n 支持。

Enhancements:

  • 将事件创建、分发、智能体准备、角色(persona)选择以及管线完成等关键生命周期节点记录到追踪流中,以提升可观测性。
Original summary in English

Summary by Sourcery

Introduce a tracing span system for message events and expose a live trace viewer in the dashboard to inspect event-level traces in real time.

New Features:

  • Add TraceSpan utility and event-level tracing hooks throughout the message pipeline to record structured trace events.
  • Add a dashboard Trace page with a real-time trace viewer fed by log history and server-sent events, including navigation entries and i18n support.

Enhancements:

  • Record key lifecycle milestones such as event creation, dispatch, agent preparation, persona selection, and pipeline completion into the trace stream for better observability.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jan 29, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:

  • TraceDisplayer 组件接收了一个 autoScroll 属性,但从未使用;建议要么把它接入 scrollToBottom 的行为,要么移除该属性,以避免造成困惑。
  • 在链路日志(TraceSpan.record 以及各处的 event.trace.record 调用)中,建议在记录前截断或清洗体积较大或敏感的载荷(例如 system_prompt、完整响应),以避免日志量过大,以及敏感数据意外泄露。
  • TraceDisplayer.vue 中有若干用户可见的字符串(例如列表头和按钮文案)被硬编码为英文;建议通过现有的 i18n 系统来驱动这些文案,使 Trace 界面能够像控制面板的其他部分一样被本地化。
给 AI Agent 的提示词
请根据以下代码评审意见进行修改:

## 总体意见
- `TraceDisplayer` 组件接收了一个 `autoScroll` 属性,但从未使用;建议要么把它接入 `scrollToBottom` 的行为,要么移除该属性,以避免造成困惑。
- 在链路日志(`TraceSpan.record` 以及各处的 `event.trace.record` 调用)中,建议在记录前截断或清洗体积较大或敏感的载荷(例如 `system_prompt`、完整响应),以避免日志量过大,以及敏感数据意外泄露。
- `TraceDisplayer.vue` 中有若干用户可见的字符串(例如列表头和按钮文案)被硬编码为英文;建议通过现有的 i18n 系统来驱动这些文案,使 Trace 界面能够像控制面板的其他部分一样被本地化。

## 单条评论

### 评论 1
<location> `astrbot/core/utils/trace.py:8-17` </location>
<code_context>
+from astrbot import logger
+from astrbot.core.log import LogQueueHandler
+
+_cached_log_broker = 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
+
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** 将 None 缓存在日志 broker 上会导致无法获取在进程生命周期后期才注册的 broker。

在 `_get_log_broker` 中,一旦没有找到 `LogQueueHandler``_cached_log_broker` 就会保持为 `None`,因此后续调用将永远看不到之后添加的 handler(例如通过动态日志配置或测试添加的 handler),并且 `TraceSpan.record` 将无法发布日志。为了支持运行时的 handler 变更,应避免缓存 `None` 结果(仅在找到 broker 时才缓存),或者提供一种方式来使缓存失效/刷新缓存。

建议实现如下:

```python
from astrbot import logger
from astrbot.core.log import LogQueueHandler

```

```python
def _get_log_broker():
    """
    Return the current log broker, if any.

    This function only caches successful lookups (a non-None broker).
    If no broker is found, it returns None without updating the cache,
    so subsequent calls can pick up handlers that are registered later
    in the process lifecycle (e.g. dynamic logging config, tests).
    """
    global _cached_log_broker

    # If we already have a cached broker, just return it.
    if _cached_log_broker is not None:
        return _cached_log_broker

    # No cached broker yet; scan handlers each time until one is found.
    for handler in logger.handlers:
        if isinstance(handler, LogQueueHandler):
            _cached_log_broker = handler.log_broker
            return _cached_log_broker

    # Don't cache the negative result; allow future re-scan.
    return None

```

如果文件的其他部分依赖 `_get_log_broker` 的不同签名或副作用(例如它们期望在不存在 broker 时设置某个全局标记),则这些调用点应当更新为使用更简单的约定:当有可用的 broker 实例时返回该实例,否则返回 `None`,并且在进程后续阶段一旦有 `LogQueueHandler` 被附加到 `logger` 上,它可能开始返回一个 broker。
</issue_to_address>

Sourcery 对开源项目免费 —— 如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The TraceDisplayer component accepts an autoScroll prop but never uses it; either wire this into scrollToBottom behavior or remove the prop to avoid confusion.
  • In the trace logging (TraceSpan.record and the various event.trace.record calls), consider truncating or sanitizing large or sensitive payloads (e.g., system_prompt, full responses) before logging to avoid excessive log volume and accidental leakage of sensitive data.
  • Several user‑visible strings in TraceDisplayer.vue (e.g., column headers and button labels) are hardcoded in English; consider driving these through the existing i18n system so the trace UI is localized like the rest of the dashboard.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `TraceDisplayer` component accepts an `autoScroll` prop but never uses it; either wire this into `scrollToBottom` behavior or remove the prop to avoid confusion.
- In the trace logging (`TraceSpan.record` and the various `event.trace.record` calls), consider truncating or sanitizing large or sensitive payloads (e.g., `system_prompt`, full responses) before logging to avoid excessive log volume and accidental leakage of sensitive data.
- Several user‑visible strings in `TraceDisplayer.vue` (e.g., column headers and button labels) are hardcoded in English; consider driving these through the existing i18n system so the trace UI is localized like the rest of the dashboard.

## Individual Comments

### Comment 1
<location> `astrbot/core/utils/trace.py:8-17` </location>
<code_context>
+from astrbot import logger
+from astrbot.core.log import LogQueueHandler
+
+_cached_log_broker = 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
+
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Caching None for the log broker prevents picking up a broker registered later in the process lifecycle.

In `_get_log_broker`, once no `LogQueueHandler` is found, `_cached_log_broker` stays `None`, so subsequent calls will never see a handler added later (e.g., from dynamic logging config or tests), and `TraceSpan.record` won’t publish. To support runtime handler changes, avoid caching the `None` result (only cache when a broker is found) or provide a way to invalidate/refresh the cache.

Suggested implementation:

```python
from astrbot import logger
from astrbot.core.log import LogQueueHandler

```

```python
def _get_log_broker():
    """
    Return the current log broker, if any.

    This function only caches successful lookups (a non-None broker).
    If no broker is found, it returns None without updating the cache,
    so subsequent calls can pick up handlers that are registered later
    in the process lifecycle (e.g. dynamic logging config, tests).
    """
    global _cached_log_broker

    # If we already have a cached broker, just return it.
    if _cached_log_broker is not None:
        return _cached_log_broker

    # No cached broker yet; scan handlers each time until one is found.
    for handler in logger.handlers:
        if isinstance(handler, LogQueueHandler):
            _cached_log_broker = handler.log_broker
            return _cached_log_broker

    # Don't cache the negative result; allow future re-scan.
    return None

```

If other parts of the file rely on `_get_log_broker` having a different signature or side-effects (e.g. they expect it to set a global marker when no broker exists), those call sites should be updated to work with the simpler contract: it returns a broker instance when available, or `None` otherwise, and may start returning a broker later in the process once a `LogQueueHandler` is attached to `logger`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Soulter Soulter merged commit 5b7805e into master Jan 30, 2026
6 checks passed
united-pooh pushed a commit to united-pooh/AstrBot that referenced this pull request Feb 19, 2026
* feat: trace

* fix(log): increase log cache size from 200 to 500

* feat(logging): add file and trace logging configuration options
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant