Skip to content

Sentry 监控接入

约 3132 字大约 10 分钟

WebSentry前端排障性能监控

2026-09-12

统计数据加载中...

前言

用户反馈页面报错时,往往只记得“刚才点了一下就坏了”。本机复现不出来,服务器日志又没有前端现场,就很难知道问题发生在哪一版、哪个页面、哪一步操作。

Sentry 可以把异常、版本、调用栈和操作线索放到一起。接入时除了让错误进后台,还要确认源码能还原、用户不会串号、敏感数据没有跟着上传,以及独立页面没有遗漏。

监控范围

浏览器页面 → 浏览器 SDK → 前端项目
服务端请求 → 服务端 SDK → 后端项目
构建流程   → source map 上传 → 还原对应产物的源码栈

前后端可以分成两个 Sentry 项目,便于分别管理错误、告警和额度;并不是技术上必须分开。DSN 指向哪个项目,事件就进入哪个项目,不要仅凭名字相似判断配置。

按实际框架选择 SDK,例如 React、Vue 或对应的 Node 服务端集成。初始化位置、错误边界和中间件顺序遵循该版本的集成方式,不把某个框架的文件原封不动复制过去。

先接异常监控,再按需要增加性能采样。Replay、日志和 Profiling 分别评估,不必一次全部打开。

配置与注入时机

配置项来源与约束
浏览器和服务端 DSN从对应 Sentry 项目的 Client Keys 获取,明确事件归属
组织、项目标识从项目设置确认,上传 source map 的目标与事件项目对应
上传 Token使用满足上传需求的最小权限凭据,仅注入构建环境,不进入前端变量或产物
release、environment从发布流程生成与注入,能追溯实际构建,不写死成上一版
SDK 与框架入口查当前依赖版本、前端启动和服务端 instrumentation 入口
trace 传播范围按自有 API 的完整 origin 和路径配置,不匹配任意子域或第三方服务
source map 目录从实际构建输出确定上传和删除范围,不使用过宽的工作区 glob
独立页面与 CSP盘点未加载主入口的页面,确认 SDK 脚本和事件上报地址允许访问

DSN 会出现在浏览器代码里,不等于上传 Token,也不授予读取事件的管理权限;但仍可能被滥用来写入垃圾事件,需要配合接收限制和额度管理。

Vite 客户端变量通常在构建时写入产物,后端环境变量则由运行进程读取。只修改服务器环境,不会自动改变已经构建的浏览器 DSN。

同批发布的前后端可以共用 release;独立发布时分别标记真实版本,并记录对应关系。source map 必须匹配实际运行的产物,不能靠相同字符串弥补构建不一致。

初始化与采样

浏览器 SDK 尽早接入启动流程,同时避免监控下载失败阻断应用。懒加载可以减轻首屏负担,但会留下初始化之前的监控窗口;“没有 DSN 就完全不打包 SDK”也需要检查构建产物,不能只凭一个判断语句保证。

服务端按框架要求在被监控模块加载前初始化。优先使用适配的官方集成;只有明确了解缺口时才手动补请求 span,不默认关闭全部自动 instrumentation。

tracesSampleRate: 0.05 为例,它控制性能 trace 采样,不是“只收 5% 的异常”。异常采样、过滤和额度分别检查。健康探测、静态资源等低价值流量可按路由规则过滤,路由名称用 /items/:id 这样的模板,避免高基数字段。

浏览器 trace 目标可以按下面的形状配置,域名和路径需要换成真实 API:

tracePropagationTargets: [
  /^\/api(?:\/|\?|$)/,
  /^https:\/\/api\.example\.com\/api(?:\/|\?|$)/,
]

检查实际请求是否带上 sentry-tracebaggage,第三方请求是否没有携带。跨域时还需后端正确处理相关 CORS 头;不要为排障直接放宽到所有域名。选项语义见 Sentry SDK 配置

用户关联与隐私清洗

如果业务确实需要按账号排障,使用登录系统已验证的稳定账号 ID;匿名事件保持匿名,不拿 IP、Cookie 或随机会话号冒充用户。

// 在登录状态确认后调用;user 来自应用已验证的账号信息
function syncMonitoringUser(user) {
  Sentry.setUser(user ? { id: String(user.id) } : null)
}

// 登录、账号切换和会话刷新成功后同步
syncMonitoringUser(authenticatedUser)

// 退出登录或会话失效时清除
syncMonitoringUser(null)

账号 ID 也属于用户相关数据,是否采集要符合产品隐私约定。昵称只有确实需要时才保留,不附带完整用户对象、邮箱、手机号或凭据。

服务端从可信会话取身份,在每个请求的隔离 scope 中设置;不要相信客户端传来的 X-User-Id,也不要把用户写入所有请求共享的全局状态。已有官方中间件提供隔离时直接使用;手动集成必须验证并发请求不会串号,参见 异步上下文隔离

关闭默认 PII 采集不等于完成脱敏。旧配置常使用 sendDefaultPii: false;当前文档已提供 dataCollection 并标记前者弃用,升级时按安装版本逐项核对,不机械替换成默认更宽松的配置。

在事件、性能数据和面包屑出站前做白名单清洗:

  • URL 去掉敏感查询参数,路径中的账号或业务标识也要处理。
  • 请求头排除 Cookie、Authorization 等凭据,请求体默认不采集。
  • extra、context、日志消息和 breadcrumb 不直接塞原始响应对象。
  • 用户仅保留约定字段;设备信息按排障需要和隐私策略保留。

错误事件的 beforeSend 不覆盖全部数据类型。性能事件、面包屑、Replay 或独立日志产品,需要各自的采集和清洗配置。最后检查实际事件载荷,而不是只看配置文件。

调用栈还原源码

source map 将压缩后的栈映射回源文件。以 Vite 为例,把上传插件合并到现有构建配置,放在其他插件之后:

import { defineConfig } from 'vite'
import { sentryVitePlugin } from '@sentry/vite-plugin'

// 此例用于要求上传映射的构建;dist 为示例输出目录
for (const key of ['SENTRY_ORG', 'SENTRY_PROJECT', 'SENTRY_AUTH_TOKEN']) {
  if (!process.env[key]) throw new Error(`缺少构建配置:${key}`)
}

export default defineConfig({
  build: { sourcemap: 'hidden' },
  plugins: [
  // 原有插件……
  sentryVitePlugin({
    org: process.env.SENTRY_ORG,
    project: process.env.SENTRY_PROJECT,
    authToken: process.env.SENTRY_AUTH_TOKEN,
    sourcemaps: {
      filesToDeleteAfterUpload: ['./dist/**/*.map'],
    },
  }),
  ],
})

合并时保留项目原有插件和构建选项。Token 由 CI 秘密存储或仓库外的受控文件注入,缺少上传凭据时按发布策略明确失败或关闭 map 生成,不留下未检查的公开映射文件。

hidden 只隐藏 JS 中的映射注释,不会阻止下载 .map。确认上传成功、映射与产物匹配,再检查最终公开目录没有不应发布的 map;上传后不要再次修改 bundle,破坏对应关系。官方示例见 Vite source map 上传

验收用真实业务文件中的受控错误,查看原始文件名和行号。控制台临时抛错只能检查上报链路,不能证明业务代码的映射正确。对公开 map URL 应返回 404/403,而不是下载到内容;仅测试一个猜测文件名也不够,还要检查发布目录。

独立页面

分享页、打印页、回调页、iframe 和独立 Worker 可能根本没有加载主应用的 SDK。逐个确认它们的执行入口,而不是认为主页面装了监控就全部覆盖。

独立浏览器页面可以使用单独的监控入口,并通过 surface 标签区分。是否共用前端项目按归属决定;Worker 则使用其环境支持的方案,不能直接照搬依赖 DOM 的浏览器初始化。

构建时确保入口产物不会被后续清理覆盖。配置如果由服务端注入 HTML,只包含允许公开的 DSN、版本等字段,使用正确转义,绝不注入上传 Token 或登录凭据。

严格 CSP 下只放行实际需要的脚本和 ingest 地址,不直接增加宽泛的 https:。监控失败不应让业务白屏,但也不能静默到永远没人发现;保留加载失败记录或外部检查。

用少量线索补齐现场

面包屑回答“出错前做了什么”,不需要每个动作单独开一个 issue:

Sentry.addBreadcrumb({
  category: 'ui',
  message: 'save.started',
  data: { screen: 'editor', source: 'button' },
})

记录动作名、阶段和结果,不上传原始搜索词、正文或完整 URL。已经被框架处理掉的异常,需要在合适的错误边界主动上报;自动捕获和手动 capture 要防止重复。

已有客户端日志回传也可以保留,但分清职责:普通过程日志用于诊断,值得处理的异常才进入错误追踪。服务端转发到 Sentry 的应只是带诊断数据的失败记录;“页面已加载”“播放器已挂载”这类过程日志原样转发,会变成事件数持续增长却没有任何错误信息的 issue,淹没真正的问题。为同一故障生成关联 ID,浏览器和服务端按约定去重;“已调用 capture”不代表远端已成功收到。

公开日志入口限制频率、载荷和字段,不接受任意对象直接转发到 Sentry。浏览器事件也不要简单改由服务端上传,再误以为 Node 上下文就是出错设备的现场。

没抛异常的问题

播放进度倒退、任务停滞或 Worker 内部状态异常,不一定产生可捕获异常。可以补充:

手段用法
有界状态缓冲保留最近一小段关键状态,异常时一起上报,不长期收集全部数据
状态哨兵检测违反业务预期的变化,排除主动操作后再报告
受控探测仅对允许的只读目标检查状态和耗时,设置超时、次数与冷却时间

fetch(..., { mode: 'no-cors' }) 的 opaque 响应不能证明服务返回成功或内容正确,不要拿 resolve 当健康检查通过。

Replay 是否值得启用,要看问题类型、环境支持、隐私和成本。它能补充部分交互现场,但不能代替业务状态采集,也不能用“非 DOM 问题一律无用”概括所有能力。

接入验收

检查项预期结果
浏览器与服务端错误各进入正确项目,版本和环境准确,避免重复事件
source map受控业务错误还原到对应源码位置,公开产物不泄露映射文件
用户生命周期登录后 ID 正确,退出后不残留,切换账号和并发请求不串号
匿名事件没有被人为补成真实账号,历史匿名事件不假定会自动补身份
数据清洗查询参数、凭据、请求体和自定义字段符合白名单
trace自有 API 按预期关联,不向第三方扩散追踪头
独立入口每种页面或执行环境都单独触发并检查,不只测 SPA
监控失效SDK 被阻止或 DSN 缺失时,业务仍可运行,有其他发现问题的途径

先在测试环境做受控错误,移除测试入口后再发布。事件是否出现、栈是否正确、敏感字段是否缺席都要实际查看,不能把 SDK 初始化成功当作验收完成。

浏览器入口根本没执行、上报被拦截或网络完全断开时,Sentry 也可能没有记录。保留服务器日志、外部拨测和告警,才能知道“没有事件”究竟是没有错误,还是监控没工作。

暂无评论

暂无评论,来添加第一条评论吧!