关于 sentry-span-streaming-js
用于将 JavaScript Sentry SDK 项目从基于事务的追踪迁移到 span 流式传输的技能。它涵盖浏览器、服务端和框架配置,以及回调与属性调整,并提供构建和运行时检查。
主要功能
- 01检测 JavaScript SDK 环境与配置
- 02为浏览器和服务端 SDK 启用流式传输
- 03调整 span 回调和标签属性
- 04替换事务回调与过滤器
- 05验证构建和 span 流式传送
适用场景
- 01将 JavaScript 应用迁移为逐个发送 span
- 02更新 beforeSendSpan 和 beforeSendTransaction 行为
- 03检查 span 可见性及回退警告
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ getsentry/ sentry-for-ai --skill sentry-span-streaming-js安装后在 Claude Code 中输入/sentry-span-streaming-js确认已加载。
详细介绍
Sentry Span 流式传输迁移(JavaScript)
从默认的基于事务的跟踪生命周期(static)迁移到 Span 流式传输(stream):Span 完成后会逐个发送,而不是在最后批量打包到一个事务中。
本技能涵盖 JavaScript SDK(Browser、Node.js、Bun、Deno、Cloudflare)。Python 请参阅 Span 流式传输(Python)。Dart/Flutter 请参阅 Span 流式传输(Dart)。
在以下情况下调用本技能
- 用户要求在 JavaScript 项目中“启用 Span 流式传输”或“迁移到 Span 流式传输”
- 用户想从基于事务的 Span 传递方式切换到流式传递
- 用户提到
traceLifecycle、spanStreamingIntegration或withStreamedSpan - 用户想降低 Span 传递延迟或按 Span 进行处理
阶段 1:检测
1.1 检测环境
# Detect if browser, server, or both
grep -rn "from '@sentry/browser'\|from '@sentry/react'\|from '@sentry/vue'\|from '@sentry/angular'\|from '@sentry/svelte'\|from '@sentry/nextjs'\|from '@sentry/nuxt'\|from '@sentry/sveltekit'\|from '@sentry/remix'\|from '@sentry/solidstart'\|from '@sentry/astro'\|from '@sentry/react-router'" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null | head -20
grep -rn "from '@sentry/node'\|from '@sentry/bun'\|from '@sentry/deno'\|from '@sentry/cloudflare'" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null | head -20
1.2 查找现有的 Sentry 配置
# Find Sentry.init calls
grep -rn "Sentry\.init\|init({" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null | head -20
# Find beforeSendSpan usage
grep -rn "beforeSendSpan" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null
# Find beforeSendTransaction usage
grep -rn "beforeSendTransaction" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null
# Find ignoreSpans usage
grep -rn "ignoreSpans" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" -l 2>/dev/null
1.3 对环境分类
根据检测结果,将每个 Sentry.init 调用分类如下:
| 环境 | 包 | 迁移路径 |
|---|---|---|
| Browser | @sentry/browser、@sentry/react、@sentry/vue、@sentry/angular、@sentry/svelte | 添加 spanStreamingIntegration() |
| 服务端 | @sentry/node、@sentry/bun、@sentry/deno、@sentry/cloudflare | 添加 traceLifecycle: 'stream' |
| 框架(两端) | @sentry/nextjs、@sentry/nuxt、@sentry/sveltekit、@sentry/remix、@sentry/astro、@sentry/solidstart、@sentry/react-router | 分别迁移客户端和服务端配置 |
阶段 2:迁移
前提条件: Sentry JavaScript SDK 版本为 >=10.66.0,且已启用跟踪(配置了 tracesSampleRate 或 tracesSampler)。
对每个 Sentry.init 调用应用更改。逐一处理上面找到的文件。
2.1 启用 Span 流式传输
服务端 SDK
在 Sentry.init() 中添加 traceLifecycle: 'stream':
// Before
Sentry.init({
dsn: '...',
tracesSampleRate: 1.0,
});
// After
Sentry.init({
dsn: '...',
tracesSampleRate: 1.0,
traceLifecycle: 'stream',
});
浏览器端 SDK
在 integrations 数组中添加 Sentry.spanStreamingIntegration()。该集成会自动启用 traceLifecycle: 'stream',无需手动设置。
// Before
Sentry.init({
dsn: '...',
integrations: [
Sentry.browserTracingIntegration(),
],
tracesSampleRate: 1.0,
});
// After
Sentry.init({
dsn: '...',
integrations: [
Sentry.spanStreamingIntegration(),
Sentry.browserTracingIntegration(),
],
tracesSampleRate: 1.0,
});
spanStreamingIntegration() 与其他集成的顺序无关紧要。
框架 SDK(客户端 + 服务端)
将浏览器迁移方式应用于客户端配置文件,将服务端迁移方式应用于服务端配置文件。常见模式如下:
| 框架 | 客户端配置 | 服务端配置 |
|---|---|---|
| Next.js | sentry.client.config.ts | sentry.server.config.ts、sentry.edge.config.ts |
| Nuxt | 模块中的客户端 Sentry.init | 模块中的服务端 Sentry.init |
| SvelteKit | src/hooks.client.ts | src/hooks.server.ts |
| Remix | entry.client.tsx | entry.server.tsx |
| Astro | 客户端初始化 | 服务端初始化 |
2.2 迁移 beforeSendSpan
如果用户有 beforeSendSpan 回调,必须使用 Sentry.withStreamedSpan() 对其进行包装,才能在流式模式下正常工作。若不使用此包装,SDK 会回退到静态模式。
回调的结构也会发生变化:
description现在是namedata现在是attributes- Span 对象从
SpanJSON变为StreamedSpanJSON
// Before (static mode)
Sentry.init({
beforeSendSpan: (span) => {
if (span.description?.includes('/health')) {
span.description = '[filtered]';
}
// 'data' contains span attributes
delete span.data?.['http.request.body'];
return span;
},
});
// After (streaming mode)
Sentry.init({
beforeSendSpan: Sentry.withStreamedSpan((span) => {
if (span.name?.includes('/health')) {
span.name = '[filtered]';
}
// 'attributes' replaces 'data'
if (span.attributes) {
delete span.attributes['http.request.body'];
}
return span;
}),
});
回调中的主要差异:
静态(SpanJSON) | 流式(StreamedSpanJSON) |
|---|---|
span.description | span.name |
span.data(处理后的属性) | span.attributes(原始属性) |
span.timestamp(结束时间) | span.end_timestamp |
span.status(可选字符串) | span.status('ok' 或 'error') |
span.op | span.attributes['sentry.op'] |
从 beforeSendSpan 返回 null 不会丢弃 Span;该返回值会被忽略,并记录一条警告。
2.3 将 setTag(s) 迁移到 setAttribute(s)
在流式模式下,标签不再适用于流式 span——只有属性适用。凡是用户通过 Sentry.setTag / Sentry.setTags 或 scope.setTag / scope.setTags 设置标签的地方(例如通过 withScope()、getCurrentScope()、getGlobalScope()),都添加对应的 setAttribute / setAttributes 调用,并使用相同的键值对,以确保数据仍能传递到 span。
标签仍可用于错误,因此保留现有的 setTag(s) 调用,并在旁边添加属性调用——不要用其中一个替换另一个。
查找现有用法:
grep -rn "\.setTag\b\|\.setTags\b\|setTag(\|setTags(" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.mjs" 2>/dev/null
执行迁移。大多数 setTag(s) 调用都位于也会生成 span 的代码路径中,因此除非调用明显仅用于错误报告,否则默认添加对应的属性调用。
// Before
Sentry.setTag('feature', 'checkout');
Sentry.setTags({ tier: 'premium', region: 'eu' });
// After — keep the tags, add matching attributes
Sentry.setTag('feature', 'checkout');
Sentry.setAttribute('feature', 'checkout');
Sentry.setTags({ tier: 'premium', region: 'eu' });
Sentry.setAttributes({ tier: 'premium', region: 'eu' });
基于 scope 的调用也同样适用:
// Before
Sentry.withScope((scope) => {
scope.setTag('job', 'sync-orders');
// ...
});
Sentry.getCurrentScope().setTag('job', 'sync-orders')
// After
Sentry.withScope((scope) => {
scope.setTag('job', 'sync-orders');
scope.setAttribute('job', 'sync-orders');
// ...
});
Sentry.getCurrentScope().setTag('job', 'sync-orders')
Sentry.getCurrentScope().setAttribute('job', 'sync-orders')
SDK >=10.66.0 起提供 setAttribute(s)——执行此步骤前,请确认满足版本要求。
2.4 移除或替换 beforeSendTransaction
beforeSendTransaction 在流式模式下不起作用。span 会单独发送,而不是批量发送为 transaction。
// Before
Sentry.init({
beforeSendTransaction: (event) => {
// This entire callback is ignored in streaming mode
if (event.transaction === '/health') {
return null;
}
return event;
},
});
根据 beforeSendTransaction 的用途选择迁移方式:
| 用途 | 流式模式替代方案 |
|---|---|
| 按名称/路由丢弃 span | 使用 ignoreSpans 选项 |
| 发送前修改 span 数据 | 使用 withStreamedSpan 配合 beforeSendSpan |
| 按 transaction 名称筛选 | 使用带有字符串/RegExp 模式的 ignoreSpans |
| 为 transaction 添加标签/上下文 | 使用 withStreamedSpan 配合 beforeSendSpan |
迁移其逻辑后,从 Sentry.init() 中移除 beforeSendTransaction 选项。
2.5 配置 ignoreSpans(可选)
ignoreSpans 在静态模式和流式模式下均有效,但筛选器会在 span 生命周期的不同阶段进行评估:
- 流式模式: 在 span 开始时进行评估。仅考虑 span 开始时可用的数据——span 名称和创建时设置的属性。
- 静态模式: 在根 span 结束时进行评估。仅考虑该时刻可用的数据——span 名称和属性。
在两种模式下,匹配成功都会阻止记录或发送该 span。由于筛选器最早可能在 span 开始时运行(流式模式),因此只有 span 名称和 span 开始时设置的属性可以保证可用——不要依赖 span 生命周期后期添加的属性。
Sentry.init({
traceLifecycle: 'stream',
ignoreSpans: [
// String match against span name
'/health',
'/ready',
// RegExp match against span name
/^OPTIONS /,
// Object filter — all conditions must match
{
op: 'middleware.handle',
name: /^corsMiddleware/,
},
// Filter by attributes (string = substring match, RegExp for patterns)
{
op: 'http.server',
attributes: {
'http.route': /^\/internal\//,
},
},
],
});
筛选对象属性:
| 属性 | 类型 | 匹配对象 |
|---|---|---|
name | string | RegExp | span 名称(描述) |
op | string | RegExp | span 操作 |
attributes | Record<string, string | RegExp | number | boolean | Array> | span 属性 |
筛选对象中指定多个属性时,所有属性都必须匹配,才会忽略该 span。
2.6 设置浏览器性能分析(可选)
在浏览器中使用 Span 流式传输时,请使用 v2 性能分析选项,而不是旧版 profilesSampleRate。旧版选项已弃用,且无法与 Span 流式传输生命周期集成。
添加 browserProfilingIntegration(),并配置以下两个 v2 选项:
// Before (legacy profiling — do NOT use with span streaming)
Sentry.init({
integrations: [
Sentry.browserTracingIntegration(),
],
tracesSampleRate: 1.0,
profilesSampleRate: 0.5, // deprecated
});
// After (v2 profiling with span streaming)
Sentry.init({
integrations: [
Sentry.spanStreamingIntegration(),
Sentry.browserTracingIntegration(),
Sentry.browserProfilingIntegration(),
],
tracesSampleRate: 1.0,
profileSessionSampleRate: 1.0,
profileLifecycle: 'trace',
});
v2 性能分析选项:
| 选项 | 类型 | 描述 |
|---|---|---|
profileSessionSampleRate | number(0–1) | 启用性能分析的用户会话百分比。默认值:0(禁用)。 |
profileLifecycle | 'trace' | 'manual' | 'trace':存在已采样的根 Span 时,性能分析器会自动运行。'manual':通过 Sentry.uiProfiler.startProfiler() / stopProfiler() 显式启动/停止性能分析器。默认值:'manual'。 |
profileLifecycle: 'trace' 要求启用追踪(tracesSampleRate 或 tracesSampler)。根 Span 开始时,性能分析器会启动;所有已采样的根 Span 均结束后,性能分析器会停止。Profile 分块每 60 秒独立发送一次,或在最后一个根 Span 结束时发送。
请勿混用旧版和 v2 选项。如果设置了 profilesSampleRate,profileSessionSampleRate 将不起作用,且 SDK 会记录警告。
第 3 阶段:验证
应用更改后,请验证迁移是否正常工作。
3.1 构建检查
# TypeScript check
npx tsc --noEmit 2>&1 | head -30
# Build
npm run build 2>&1 | tail -20
3.2 运行时验证
指导用户在浏览器开发者工具或服务日志中进行验证:
- 检查网络选项卡:Span 信封应作为单独请求出现,内容类型为
application/vnd.sentry.items.span.v2+json,而不是事务信封 - 检查 Sentry 仪表板:Span 完成后不久就应出现在 Traces 视图中,无需等待整个事务结束
- 检查回退警告:如果 SDK 记录了回退到静态模式的警告,则
beforeSendSpan回调可能缺少withStreamedSpan包装器
3.3 常见问题
| 症状 | 原因 | 修复方法 |
|---|---|---|
| SDK 回退到静态模式 | beforeSendSpan 未使用 withStreamedSpan 包装 | 包装回调:Sentry.withStreamedSpan(callback) |
未调用 beforeSendTransaction | 流式模式下的预期行为 | 将逻辑迁移到 beforeSendSpan 或 ignoreSpans |
| Span 仍以事务形式到达 | 未设置 traceLifecycle,或缺少集成 | 服务端:添加 traceLifecycle: 'stream';浏览器:添加 spanStreamingIntegration() |
span.description 上出现类型错误 | StreamedSpanJSON 使用 name 而非 description | 在回调中将 span.description 改为 span.name |
span.data 上出现类型错误 | StreamedSpanJSON 使用 attributes 而非 data | 在回调中将 span.data 改为 span.attributes |
profileSessionSampleRate 无效 | 同时设置了旧版 profilesSampleRate | 移除 profilesSampleRate,仅使用 profileSessionSampleRate + profileLifecycle |
| Span 缺少标签 | 标签不适用于流式传输的 Span | 在现有 setTag(s) 调用旁添加对应的 setAttribute(s) 调用 |
快速参考
最简服务端配置
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: '__DSN__',
tracesSampleRate: 1.0,
traceLifecycle: 'stream',
});
最简浏览器配置
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: '__DSN__',
integrations: [
Sentry.spanStreamingIntegration(),
Sentry.browserTracingIntegration(),
],
tracesSampleRate: 1.0,
});
含性能分析的浏览器配置
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: '__DSN__',
integrations: [
Sentry.spanStreamingIntegration(),
Sentry.browserTracingIntegration(),
Sentry.browserProfilingIntegration(),
],
tracesSampleRate: 1.0,
profileSessionSampleRate: 1.0,
profileLifecycle: 'trace',
});
完整迁移清单
- SDK 版本为
>=10.66.0 - 服务端配置:已添加
traceLifecycle: 'stream' - 浏览器配置:已添加
spanStreamingIntegration() -
beforeSendSpan回调已使用Sentry.withStreamedSpan()包装 -
beforeSendSpan回调已更新:description->name,data->attributes -
setTag(s)/scope.setTag(s)调用已配套添加对应的setAttribute(s)调用 -
beforeSendTransaction逻辑已迁移到beforeSendSpan或ignoreSpans - 已从配置中移除
beforeSendTransaction - (如果启用了性能分析)已将
profilesSampleRate替换为profileSessionSampleRate+profileLifecycle - (如果启用了性能分析)已将
browserProfilingIntegration()添加到 integrations - 构建通过,且没有类型错误
- Sentry 仪表板中可见 Span