Sentry
快速开始
使用 Sentry 蓝图为现有 Flue 项目添加 Sentry 可观测性。在终端或你选择的编码智能体中运行以下命令:
flue add tooling sentry
概述
Sentry 蓝图会在源代码根目录创建 sentry.ts,并从 app.ts 中导入一次。它传递三个信号,每个对话共享一个跟踪:终端失败作为问题,每个 log.* 调用作为 Sentry 日志,并且当 SENTRY_TRACES_SAMPLE_RATE > 0 时,Flue 的 invoke_agent → chat / execute_tool 跨度层次结构包含令牌使用量,遵循 OpenTelemetry GenAI 语义约定。在 Node.js 上,生成的集成核心如下所示:
import { createOpenTelemetryInstrumentation } from '@flue/opentelemetry';
import { instrument } from '@flue/runtime';
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
enabled: Boolean(process.env.SENTRY_DSN),
tracesSampleRate, // 从 SENTRY_TRACES_SAMPLE_RATE 钳制,默认 0
traceLifecycle: 'stream', // 交付比其父代存活更久的 gen_ai 子代
streamGenAiSpans: true,
enableLogs: true,
integrations: (defaults) => defaults.filter((i) => !SENTRY_AI_PROVIDER_INTEGRATIONS.has(i.name)),
});
// Sentry 拥有全局 OTel 跟踪器提供者,因此 Flue 的跨度直接落入
// Sentry;内容策略将模型/工具内容排除在跟踪之外,除非记录标志选择加入。
if (tracesSampleRate > 0) {
instrument(createOpenTelemetryInstrumentation({ content: contentPolicy() }));
}
instrument({
key: Symbol.for('flue.sentry.bridge'), // 开发重新加载替换,从不堆叠
observe(event) {
if (event.type === 'operation' && event.isError) {
// 问题从实时 `errorInfo` 构建,它携带抛出位置堆栈;
// 跳过失败提交的结算,因此每个失败恰好引发一个问题。
captureTerminalFailure(event.errorInfo ?? event.error, correlationTags(event));
if (event.submissionId) capturedFailedSubmissions.add(event.submissionId);
return;
}
if (event.type === 'submission_settled') {
/* 仅捕获未捕获的失败 */
}
if (event.type === 'log') {
Sentry.logger[event.level](event.message, logAttributes(event));
}
},
interceptor: (_operation, _ctx, next) => next(),
async dispose() {
await Sentry.flush(2000);
},
});在 Cloudflare 上,生成的 sentry.ts 包含相同的桥接和检测,但不调用 Sentry.init()。相反,蓝图向每个智能体添加模块本地的 cloudflare 扩展。该扩展使用 instrumentDurableObjectWithSentry(...) 包装最终生成的 Durable Object 类,该函数在每个隔离区初始化 SDK(包括跟踪和日志),同时保持外部 Worker 未检测。
配置
| 变量 | 用途 |
|---|---|
SENTRY_DSN | 事件交付必需 — 标识 Sentry 项目并允许事件提交。 |
SENTRY_ENVIRONMENT | 可选 — 在 Sentry 中标识部署环境。 |
SENTRY_RELEASE | 可选 — 将事件与已部署的发布关联。 |
SENTRY_TRACES_SAMPLE_RATE | 可选 — 0 到 1。0(默认)仅发送错误和日志;高于 0 还发送 AI 跟踪。 |
SENTRY_AI_RECORD_INPUTS | 可选 — true 在跟踪跨度中包含提示、指令和工具定义/参数。 |
SENTRY_AI_RECORD_OUTPUTS | 可选 — true 在跨度中包含模型输出、工具结果和异常消息/堆栈。 |
交付事件只需要 SENTRY_DSN。Sentry DSN 允许事件提交,但不授予对项目数据的读取访问权限。将其保留在部署配置中而不是应用源代码中,使轮换和滥用缓解更容易;根据你项目的策略使用密钥或环境绑定。
蓝图会安装 @sentry/node 或 @sentry/cloudflare 加上 @flue/opentelemetry,在适当的运行时边界初始化 SDK,并通过 instrument(...) 注册事件桥接和跨度检测。模型和工具内容保留在跟踪之外,除非记录标志选择加入。
有关 Sentry 与 OpenTelemetry 和 Braintrust 的比较,请参阅可观测性。
集成按目标使用不同的 SDK:
- Node.js —
@sentry/node,在应用源代码中使用模块范围的Sentry.init(...)初始化。 - Cloudflare —
@sentry/cloudflare,使用instrumentDurableObjectWithSentry(...)围绕每个生成的智能体 Durable Object 初始化。
不要在 Cloudflare 上使用 @sentry/node。
选择报告内容
生成的集成报告:
- 问题 — 带有
isError: true的operation事件(失败的提示、技能、任务、shell 或压缩操作)和带有outcome: 'failed'的submission_settled事件,这些事件未从其操作中捕获,因此一个失败引发一个问题; - 日志 — 每个
log.info、log.warn和log.error调用在 Sentry 日志中以其自身级别显示,带有清理后的属性和跟踪关联。错误日志是日志,不是问题:报告可恢复错误并继续的智能体永远不会引发问题; - 跟踪 — Flue 的 OpenTelemetry 检测发出的跨度层次结构,由
SENTRY_TRACES_SAMPLE_RATE采样。Sentry 自己的 AI 提供商集成被抑制,因此模型调用不会被重复计算。
捕获包括 flue.* 关联标签 — 智能体实例、智能体名称、对话、会话、操作和提交 — 与跟踪跨度上的属性匹配。有关 Flue 的身份和观察器模型,请参阅可观测性。
当记录标志关闭时,跨度携带时序、令牌使用量、模型标识符和关联 ID,但没有消息或工具内容。启用记录标志会将该方向的内容通过带有 16 KiB 每属性预算的清理转换路由。在扩大该策略之前,请做出明确的数据处理决策。
目标行为
在 Node.js 上,模块范围的初始化足以满足桥接的捕获和 Flue 的跨度。完成 Sentry HTTP 或数据库自动检测需要在应用导入之前进行 Sentry 的预加载设置,并应针对构建的 Flue 服务器进行验证。关闭刷新是尽力而为的:SIGINT/SIGTERM 监听器调用 Sentry.flush(...) 而不拥有进程退出,因此运行期间发送的跟踪和问题是安全的,而最近缓冲的日志可能会被截断。
在 Cloudflare 上,Flue 对每个检测的智能体的最终生成的 Durable Object 类应用模块本地的 wrap 扩展。这保留了 Flue 的路由和持久性行为,同时允许 Sentry 从当前绑定环境初始化,每个隔离区一次。包装器不覆盖外部 Worker 或编写的 Hono 应用;当需要请求检测时,单独添加 HTTP 中间件。
验证
针对非生产 Sentry 项目使用 SENTRY_TRACES_SAMPLE_RATE=1,提示一个使用工具的智能体,并确认一个带有 invoke_agent、chat 和 execute_tool 跨度的跟踪,加上其在 Sentry 日志中的日志。触发一个终端失败,并确认恰好有一个带有原始错误和抛出位置堆栈的问题。确认预期的 flue.* 关联字段,当记录标志关闭时没有模型内容出现,在 Cloudflare 上包装的智能体从工作线程交付,以及应用在没有配置 DSN 的情况下仍然启动。