错误追踪与 Source Map:去重、还原与 Release
基于 Sentry 8.x · 核于 2026-08
速查
- 错误采集流程:应用抛异常 → SDK 捕获(全局未处理异常 hook)→ 收集 stack trace + 环境 + 用户 + 请求上下文 → 上报 Sentry → fingerprint 去重归并 issue。
- Event vs Issue:Event 是单次错误(每次抛出一条);Issue 是同源错误的归并组(按 fingerprint)。一个 issue 下挂多个 event,issue 页显示聚合统计(次数/用户数/趋势)。
- fingerprint 指纹:默认基于 stack trace 关键帧(错误类型 + 出错文件 + 函数 + 行号)算指纹,栈相同的归为同一 issue——避免同源错误刷屏。
- 自定义 fingerprint:
Sentry.withScope(scope => scope.setFingerprint([...])),用于动态参数导致默认分组不准的场景(如「订单 ID 不同但本质同源」按错误类型分组)。 - Source Map 上传:CI/CD 构建后用
sentry-cli sourcemaps upload --release v1.2.0 dist/上传,Sentry 据此还原压缩栈到源码行。 - Source Map 安全:Source Map 不要部署到生产 CDN(暴露源码),只上传 Sentry 内部。
- Release tracking:SDK 初始化传
release: 'v1.2.0',上传 Source Map 带 release → Sentry 标记错误首次出现的版本 + 关联 commit + 检测回归。 - 回归检测(regression):某错误在 release A 标记 resolved,在 release B 又出现 → 自动标记 regression,提醒修复失效。
- issue 状态机:unresolved(待修)→ assigned(已分配)→ resolved(已修)/ ignored(忽略)。resolved 后又出现触发 regression。
一、错误采集:从异常到 Event
Sentry SDK 通过 hook 全局未处理异常采集错误:
前端(浏览器)
js
// React 应用(@sentry/react)
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://xxx@sentry.io/123", // 项目唯一标识
release: "myapp@1.2.0", // 版本(Release tracking)
environment: "production",
tracesSampleRate: 0.2, // 性能采样率(20%)
replaysSessionSampleRate: 0.1, // Session Replay 采样
});
// SDK 自动 hook:
// - window.onerror(同步错误)
// - window.onunhandledrejection(Promise 未捕获 reject)
// - fetch/XHR(请求错误)
// - console.error(可选)后端(Python/Node)
python
# Python(sentry-sdk)
import sentry_sdk
sentry_sdk.init(
dsn="https://xxx@sentry.io/123",
release="myapi@1.2.0",
traces_sample_rate=0.2,
)
# SDK 自动 hook:
# - sys.excepthook(未捕获异常)
# - logging(ERROR 级日志)
# - Django/Flask/FastAPI 框架中间件
# - DB 查询(SQLAlchemy/Django ORM)- 采集的上下文:stack trace(核心)+ environment(生产/测试)+ release + 用户信息(user_id/email/IP)+ 请求信息(URL/method/headers)+ 自定义 tags/extra。
- 采样:高流量场景 SDK 配置采样率(如
tracesSampleRate: 0.2只上报 20% 性能 trace),错误事件默认全采(不采样,因为错误稀有且重要)。
二、fingerprint 去重:同源错误归一
Sentry 的核心智能是把同源错误归为一组(issue),靠 fingerprint:
默认指纹算法
错误事件到达 → Sentry 取 stack trace
→ 提取关键帧(错误类型 + 出错文件 + 函数名 + 行号)
→ 算 fingerprint(哈希)
→ 指纹相同的归为同一 issue
→ 新指纹创建新 issue(标「新错误」)- 默认分组合理:同一处代码抛同一类型异常,栈相同 → 同一 issue。不同代码路径抛同类异常 → 不同 issue(即使错误类型相同)。
- issue 聚合:issue 页显示首次/末次出现时间、总 event 数、影响用户数、stack trace、趋势图——一眼看错误严重度与趋势。
自定义 fingerprint
某些场景默认分组不准:
js
// 例:订单查询失败,错误信息含订单 ID,默认按消息分组会让每个订单一个 issue
try {
await getOrder(orderId);
} catch (e) {
Sentry.withScope(scope => {
// 强制按错误类型分组,忽略消息中的动态订单 ID
scope.setFingerprint(["{{ default }}", "order-fetch-error"]);
Sentry.captureException(e);
});
}- 何时自定义:动态参数(ID/时间戳)导致同源错误被拆成多 issue;或反过来想把不同栈的错误合并。
{{ default }}:占位符,保留默认指纹 + 追加自定义维度。
三、Source Map:还原压缩栈到源码
生产前端代码压缩后,报错栈无法定位:
压缩栈(用户报错):
at handleLogin (https://cdn.com/app.min.js:1:23456)
at HTMLButtonElement.onclick (https://cdn.com/app.min.js:1:45678)
问题:app.min.js 是几万行压缩成一行的,1:23456 无法定位源码Source Map 解决
构建产物:
dist/assets/app-[hash].js (压缩混淆的生产代码)
dist/assets/app-[hash].js.map (Source Map,记录映射)
流程:
1. CI 构建后上传 Source Map 到 Sentry
sentry-cli sourcemaps upload --release myapp@1.2.0 dist/assets/
2. 用户报错栈:app-[hash].js:1:23456
3. Sentry 查该 release 的 Source Map:1:23456 → src/components/Login.tsx:42
4. 展示还原栈:
at handleLogin (src/components/Login.tsx:42)
at onSubmit (src/components/Login.tsx:28)上传命令(sentry-cli)
bash
# 安装
npm i -g @sentry/cli
# 配置(CI 环境变量)
export SENTRY_AUTH_TOKEN=xxx
export SENTRY_ORG=my-org
export SENTRY_PROJECT=my-frontend
# 上传(构建后)
sentry-cli sourcemaps upload \
--release myapp@1.2.0 \ # 与 SDK init 的 release 一致
--dist 1 \ # 可选,区分部署目标
dist/assets/
# 或用 sentry-webpack-plugin / @sentry/vite-plugin 自动化安全注意事项
- 不要部署 Source Map 到生产 CDN:Source Map 含完整源码映射,公开访问等于泄露源码。只上传到 Sentry,构建产物(dist)只发压缩 JS,不发 .map。
- Webpack
hidden-source-map:生成 Source Map 但不在 JS 末尾引用(浏览器不加载,仅 Sentry 用)。 - 后端 Debug Symbol:Python/Java/Go 的二进制栈要靠符号表(symbol)还原,类似 Source Map。
四、Release tracking:版本关联
Sentry 把 release 作为一等概念,关联错误与版本:
js
Sentry.init({
release: "myapp@" + process.env.npm_package_version, // v1.2.0
});- 标记首次出现:每个错误标「首次出现在 release v1.2.0」,结合该 release 的 commit 范围,知道是哪个 commit 引入的。
- 关联 commit:用
sentry-cli releases set-commits把 release 与 git commit 范围关联,issue 页直接显示「可能引入此错误的 commit」。 - 部署追踪:
sentry-cli releases deploys new记录部署(环境/时间),看版本在哪些环境部署。 - 采用率(adoption):SDK 上报时带 release,Sentry 统计每个 release 覆盖的用户比例(版本发布后扩散速度)。
五、回归检测(regression)
Sentry 自动检测「修复后又重现」的错误:
release v1.0.0:错误 A 出现 → issue 创建
release v1.1.0:开发者修复错误 A → issue 标 resolved
release v1.2.0:错误 A 又出现 → Sentry 自动标 regression(回归)
→ 告警「修复失效」,提醒重新审视- 价值:避免「修了又坏」的隐性回归被忽视。传统日志系统做不到(没有 issue 状态)。
- 依赖 Release tracking:必须有准确的 release 标记,Sentry 才能算「在哪个版本又出现」。
六、issue 状态机
每个 issue 有状态,像工单系统:
| 状态 | 含义 |
|---|---|
| unresolved | 待处理(默认) |
| assigned | 已分配给某人 |
| resolved | 已修复(手动或 merge PR 自动) |
| ignored | 忽略(已知问题不修,如第三方 bug) |
| regression | resolved 后又出现(自动标记) |
- 自动 resolved:上传新 release 时,可配置「标记该 release 之前的所有 issue 为 resolved」(假设新版本修复了)。
- Suspect Commits:issue 页显示「可能引入此错误的 commit」(基于 Release 关联),加速定位。
下一步
掌握了错误追踪与 Source Map 后,下一步看性能监控与 Session Replay——Performance trace 慢请求、Replay 录制回放、前后端全栈集成与 APM 边界。