Sentry 配置实践:前后端项目划分、日志、追踪、Source Map 与 CLI 迁移
8月 11, 2026
AI 参与说明(Agent:Codex):本文以 Sentry 官方文档为主要依据,并用相关运行时的官方文档校验案例。本文给出的是前端与后端应用共用的 Sentry 配置原则;SDK、套餐能力与部署配置可能变化,实施前请按文末来源和当前版本复核,并审查数据采集范围。
先说结论:前端与后端通常建两个 Project#
对于绝大多数同时包含浏览器前端与服务端/后端的应用,推荐在同一个 Sentry Organization中创建两个 Project:一个接收浏览器数据,一个接收后端数据。这里的“后端”可以是 Node 服务、Serverless Function、Cloudflare Worker、BFF 或 SSR runtime;技术栈不改变这个边界。
| Sentry Project | 接收什么 | DSN 放在哪里 |
|---|---|---|
myapp-web(浏览器前端,例如 React) | 浏览器错误、浏览器结构化日志、前端性能数据、可选的 Replay | 浏览器构建时注入的公开配置,例如 VITE_SENTRY_WEB_DSN |
myapp-server(后端) | API/SSR/后台任务异常、服务端日志、服务端 trace | 服务端运行时的环境变量或 binding,例如 SENTRY_SERVER_DSN |
这不是“每个仓库必须有一个 Project”的规则。Sentry 将 Project 定义为错误归属、入站过滤、告警、所有权和 Issue 分组的边界,并明确建议:即使是单体代码库,也应把前端与后端分开;其 DSN 文档还直接以 React 前端与 Express 后端(即使同一 monorepo)为两个 Project、两个 DSN 的例子。Sentry Organization 指南 DSN 说明
flowchart LR B["浏览器\nSPA / hydration"] -->|"web DSN"| W["Sentry Project\nmyapp-web"] C["后端\nAPI · SSR · job"] -->|"server DSN"| S["Sentry Project\nmyapp-server"] B -->|"sentry-trace + baggage"| C W -. "同一 Organization\n同一 release / environment" .- S
两个 Project 不会妨碍浏览器请求与后端请求成为同一条分布式 trace。浏览器只应向自己的 API 域名传递 sentry-trace 和 baggage;跨域时还要在 CORS 中允许这两个 header。后端可以选择启用 strictTraceContinuation;该选项校验的是Organization ID而不是 Project ID,因此两个 Project 只要仍在同一 Organization 中即可安全续接 trace。Sentry 配置选项
何时可以先用一个 Project?#
小型个人项目、PoC,且浏览器和后端由同一人值守、使用同一套告警/脱敏/配额策略时,一个 Project 技术上可行。这是可运行的简化路径,不是项目划分的最佳默认值。
若这样做,至少给事件和日志设置稳定的 service/runtime 属性,分别标识 web 与 server。一旦需要不同的告警、值班人、PII 策略、Issue 分组或 source map 发布流程,就拆成两个 Project。
先配置这些 Sentry 通用边界#
1. DSN、环境与 release#
DSN 是事件上报地址,不是读取数据的凭据:浏览器的 VITE_SENTRY_WEB_DSN 可以公开;SENTRY_AUTH_TOKEN 则是上传 source map 或 release 的构建凭据,必须只存在于 CI/构建环境,不能进入浏览器 bundle 或后端 runtime。每个 Project 使用自己的 DSN。Sentry DSN 说明
不要为 production、staging、preview 再创建一套 Project。它们应使用同一组 Project,并通过一致的 environment 值筛选和告警;浏览器与后端应写入相同的、不可变的 release(通常是 Git SHA 或 CI build ID),这样 Sentry 才能把同一版本的错误、trace 和 source map 对齐。Sentry Environments
2. 错误、日志、性能与隐私#
- 错误事件通常保留完整采样;性能 trace、Replay 和日志应按流量、预算与关键路由独立采样,生产环境不要照抄
tracesSampleRate: 1。 enableLogs: true只启用 Sentry Logs。业务代码优先使用Sentry.logger.发送少量结构化日志;已有console.需要显式启用consoleLoggingIntegration,通常仅保留warn/error。- 采集配置是隐私边界。需审查 user、cookie、header、URL query、HTTP body 与日志字段;在
beforeSend/beforeSendLog中删除 token、密码和原始敏感数据。关闭某一类自动采集并不等于不再发送 PII。
3. Trace 与 source map#
浏览器的 tracePropagationTargets 仅匹配自有 API;后端 SDK 继续传入/传出的 trace。浏览器 bundle 的 source map 上传到 myapp-web,后端 bundle 的 source map 上传到 myapp-server,两边使用相同 release。Vite 等构建工具应生成 hidden map,并在上传后删除或拒绝公开访问 .map 文件。Sentry JavaScript Logs Sentry Vite source maps
案例:TanStack Start SSR 的后端部署在 Cloudflare Workers#
以下示例假设使用当前 TanStack Start 的 Cloudflare Workers 部署方式:@cloudflare/vite-plugin、wrangler.jsonc 和 nodejs_compat。TanStack Start 的官方 hosting 文档给出了该部署基线;Sentry 的 Cloudflare 专用指南要求将自定义 server entry 用 withSentry 包裹。TanStack Start Hosting Sentry Cloudflare + TanStack Start
1. 安装运行时 SDK#
pnpm add @sentry/cloudflare @sentry/tanstackstart-react@sentry/tanstackstart-react 当前仍标注为 Beta,且其官方包声明 TanStack Start 最低兼容版本为 1.111.12;请将所有 @sentry/* 依赖保持在兼容的同一版本线上,而不是单独升级其中一个包。官方包说明
2. 让 Worker 使用自定义 server entry#
// wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "myapp",
"main": "src/server.ts",
"compatibility_date": "2026-08-11",
"compatibility_flags": ["nodejs_compat"],
"vars": {
"SENTRY_ENVIRONMENT": "production",
"SENTRY_RELEASE": "myapp@<git-sha>"
}
}把 SENTRY_WORKER_DSN 作为部署 binding 设置,例如:
pnpm exec wrangler secret put SENTRY_WORKER_DSNDSN 本身可以公开:它只能提交事件,不能读取 Sentry 数据。因此浏览器中使用 VITE_* 形式的 DSN 是正常做法;但 SENTRY_AUTH_TOKEN 是 source map/release 上传用的构建凭据,绝不能进入浏览器 bundle 或 Worker runtime。DSN 安全性 Vite source maps
3. Worker 侧:包住 TanStack Start 的 fetch handler#
// src/server.ts
import * as Sentry from "@sentry/cloudflare";
import { wrapFetchWithSentry } from "@sentry/tanstackstart-react";
import handler from "@tanstack/react-start/server-entry";
interface Env {
SENTRY_WORKER_DSN: string;
SENTRY_ENVIRONMENT: string;
SENTRY_RELEASE: string;
}
export default Sentry.withSentry(
(env: Env) => ({
dsn: env.SENTRY_WORKER_DSN,
environment: env.SENTRY_ENVIRONMENT,
release: env.SENTRY_RELEASE,
enableLogs: true,
// 示例起点;应根据真实流量、预算和关键路由改成 sampler。
tracesSampleRate: 0.1,
// 这里只关闭两类自动采集;其余类别仍须按隐私策略显式审查。
dataCollection: {
userInfo: false,
httpBodies: [],
},
}),
// TanStack Start 与 Cloudflare handler 的类型不同;官方示例要求保留此注释。
// @ts-expect-error - handler is not typed as a Cloudflare handler
wrapFetchWithSentry(handler),
);withSentry 负责 Worker 请求生命周期中的初始化、异常与 trace;wrapFetchWithSentry 为 TanStack Start 的 server 函数增加 tracing。不要改用 TanStack Start 的 Node --import 初始化教程:Sentry 明确标注那条路径不适用于 Cloudflare 部署。
dataCollection 是一个必须认真审查的隐私边界。当前 SDK 默认会收集丰富调试上下文;只写 userInfo: false 和 httpBodies: [] 并不等于“没有 PII”。生产环境还应按数据分类显式检查 header、cookie、URL query 和业务日志,并在 beforeSend/beforeSendLog 中移除 token、密码、身份证明和原始请求体。dataCollection 选项
4. 框架级 Server Function / 请求中间件#
将 Sentry 中间件放在 TanStack Start 的数组首位:
// src/start.ts
import {
sentryGlobalFunctionMiddleware,
sentryGlobalRequestMiddleware,
} from "@sentry/tanstackstart-react";
import { createStart } from "@tanstack/react-start";
export const startInstance = createStart(() => ({
requestMiddleware: [sentryGlobalRequestMiddleware],
functionMiddleware: [sentryGlobalFunctionMiddleware],
}));这里有一个容易漏掉的边界:上述中间件不会自动捕获 SSR 渲染异常。如果业务代码或自定义错误边界捕获了渲染异常,应在唯一的兜底点调用 Sentry.captureException(error),随后继续返回对应的错误响应或 fallback UI;不要在多个边界重复上报同一个错误。
5. 浏览器侧:尽早初始化,再挂上 router tracing#
浏览器使用 myapp-web 的 DSN,Worker 使用 myapp-worker 的 DSN。Cloudflare 专用页给出了在 router.tsx 内一次性 init 的简化方式;当前 TanStack Start 手动配置指南则推荐将初始化拆出来,并把它作为 client entry 的第一个 import。后者能捕获 hydration 前和其他模块初始化期间的错误,下面采用它。
// src/instrument.client.ts
import * as Sentry from "@sentry/tanstackstart-react";
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_WEB_DSN,
environment: import.meta.env.VITE_SENTRY_ENVIRONMENT,
release: import.meta.env.VITE_SENTRY_RELEASE,
enableLogs: true,
integrations: [
// 可选:只采集高价值的旧 console 调用,避免无差别上传。
Sentry.consoleLoggingIntegration({ levels: ["warn", "error"] }),
],
tracesSampleRate: 0.1,
// 仅把 trace header 发往本应用的 API / Worker;按实际域名调整。
tracePropagationTargets: [/^\//, /^https:\/\/api\.example\.com/],
});// src/client.tsx
// 必须是第一个 import。
import "./instrument.client";
import { StartClient } from "@tanstack/react-start/client";
import { StrictMode, startTransition } from "react";
import { hydrateRoot } from "react-dom/client";
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<StartClient />
</StrictMode>,
);
});// src/router.tsx
import * as Sentry from "@sentry/tanstackstart-react";
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
export const getRouter = () => {
const router = createRouter({ routeTree });
if (!router.isServer) {
Sentry.addIntegration(
Sentry.tanstackRouterBrowserTracingIntegration(router),
);
}
return router;
};VITE_SENTRY_WEB_DSN、VITE_SENTRY_ENVIRONMENT 和 VITE_SENTRY_RELEASE 是构建时注入的公开浏览器配置;Worker binding 不能在浏览器运行时直接读取。因此发布流水线应将同一个不可变 release 值(通常是 Git SHA 或 CI build ID)同时写给浏览器和 Worker,而环境值也要一致。TanStack Start 手动配置:浏览器初始化与 Router tracing
6. 日志不是自动收集全部 console#
enableLogs: true 只启用 Sentry Logs 能力;推荐业务代码显式发送少量、可查询的结构化日志:
Sentry.logger.info("checkout completed", {
order_id: order.id,
item_count: order.items.length,
payment_provider: "stripe",
});要将历史 console.* 调用作为 Sentry Logs 发送,需要像上例那样额外启用 consoleLoggingIntegration。生产环境通常只选 warn/error,并用 beforeSendLog 过滤 debug 噪声和敏感字段。日志会与活动 trace 关联,但日志、错误事件和浏览器 breadcrumbs 是不同的数据产品,不能把其中任意一种当作另外两种的替代。Sentry Logs
7. Source maps 与验证#
两个 Project 时,source map 也必须按运行时分流:浏览器 bundle 上传至 myapp-web,Worker bundle 上传至 myapp-worker;两边使用相同 release。不要让一个覆盖整个 SSR 构建的 Vite 上传步骤把所有 maps 错传到前端 Project。
- 浏览器 Vite 构建可使用
@sentry/vite-plugin;它必须放在其他 Vite plugin 之后,生成hiddensource map,并在上传后删除.map文件。 - Worker 侧遵循 Sentry 的 Cloudflare source map 流程;官方指南要求配置
upload_source_maps,并用npx @sentry/wizard@latest -i sourcemaps完成对应项目的上传设置。 - Sentry Cloudflare Vite plugin 可提供额外的 Worker 依赖插桩,但当前标注为 experimental,且需要
nodejs_compat;它不是基础异常采集的前置条件。
发布后至少做三次验证:浏览器点击按钮抛出异常、请求一个会在 Worker 端抛错的 API 路由、发送一条 Sentry.logger.info。确认错误分别进入正确 Project、栈已还原到源文件,且一次浏览器到 API 的请求能在 Trace Explorer 中关联。Sentry 的官方 Cloudflare + TanStack Start 指南提供了相同的浏览器与 API 验证思路。Cloudflare source maps Cloudflare Vite plugin
案例:纯 Vite + TanStack Router SPA 只需要一个浏览器 Project#
这里没有 SSR、Worker server entry 或服务端函数。创建一个 React 类型的 myapp-web Project 即可,使用 @sentry/react,不要安装 @sentry/tanstackstart-react 或 @sentry/cloudflare 来替代它。
pnpm add @sentry/react
pnpm add -D @sentry/vite-pluginSentry 的 TanStack Router 集成包含在 @sentry/react 中,兼容 @tanstack/react-router >= 1.64.0。它应在 router 创建之后、RouterProvider 渲染之前初始化,并使用专门的 tanstackRouterBrowserTracingIntegration,而不是通用的 browserTracingIntegration。Sentry TanStack Router 集成
// src/router.tsx
import * as Sentry from "@sentry/react";
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
export const router = createRouter({
routeTree,
// 路由 ErrorBoundary 捕获的错误在这里上报,并保留 React component stack。
defaultOnCatch: (error, errorInfo) =>
Sentry.captureReactException(error, errorInfo),
});
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN,
environment: import.meta.env.MODE,
release: import.meta.env.VITE_SENTRY_RELEASE,
enableLogs: true,
integrations: [
Sentry.tanstackRouterBrowserTracingIntegration(router),
Sentry.consoleLoggingIntegration({ levels: ["warn", "error"] }),
],
tracesSampleRate: import.meta.env.PROD ? 0.1 : 1.0,
tracePropagationTargets: [/^\//],
});
declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
}路由层已使用 defaultOnCatch 时,不要再用 React 19 的 createRoot({ onCaughtError: … }) 对同一类路由 ErrorBoundary 重复上报。未捕获错误仍由 SDK 自动采集;React 19 的 onUncaughtError/onRecoverableError 或局部 <Sentry.ErrorBoundary> 可以按需要作为额外 UI/诊断边界,但应明确每种错误只由一个路径报告。
若使用文件路由,Vite 配置还需兼顾三个 plugin 的顺序:TanStack Router 在 React 前,Sentry 在所有 plugin 后。SENTRY_AUTH_TOKEN 仅在 CI 或被 Git 忽略的构建环境文件中读取,不能加 VITE_ 前缀。
// vite.config.ts
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import { tanstackRouter } from "@tanstack/router-plugin/vite";
import { sentryVitePlugin } from "@sentry/vite-plugin";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
return {
build: { sourcemap: "hidden" },
plugins: [
tanstackRouter({ target: "react", autoCodeSplitting: true }),
react(),
sentryVitePlugin({
org: env.SENTRY_ORG,
project: env.SENTRY_PROJECT,
authToken: env.SENTRY_AUTH_TOKEN,
sourcemaps: {
filesToDeleteAfterUpload: ["./dist/**/*.map"],
},
}),
],
};
});TanStack 官方要求 Router Vite plugin 在 React plugin 前;Sentry 官方要求 Vite plugin 在全部其他 plugin 后,并提醒它不会在 watch/development 模式上传 source map。生产构建后用一次故意抛错来验证 source map,而不是只看构建成功。TanStack Router + Vite Sentry Vite source maps
Convex 有 Sentry 方案吗?有,但它是异常上报,不是完整 SDK 接入#
Convex 提供内建 Sentry Exception Reporting。它适合把 Convex 的 query、mutation、action 与 http_action 执行异常发到 Sentry:在 Convex Dashboard 的 Deployment Settings → Integrations → Sentry 中填写 DSN,并在 Sentry 创建一个Node.js 平台的 Project。该内建功能当前需要 Convex Pro 计划。Convex Exception Reporting
如果同一产品同时有浏览器、Cloudflare Worker 和 Convex,通常形成第三个 Project:
| 运行时 | 推荐 Project | 说明 |
|---|---|---|
| 浏览器 | myapp-web | React / TanStack Router 或 TanStack Start 客户端 |
| Cloudflare Worker | myapp-worker | SSR、HTTP、Worker 日志与 trace |
| Convex | myapp-convex(Node.js) | Convex 函数异常 |
Convex 会附加不可覆盖的 func、func_type、func_runtime、request_id、server_name、environment 和认证用户标识等标签。这使它适合按函数和请求 ID 排查异常;事件可能需要一两分钟才显示在 Sentry。
它的边界也很重要:Convex 官方明确说明内建 Sentry 支持尚不提供 Sentry SDK 的高级自定义能力。因此不要把它当成 Convex 中已经有 Sentry.logger、完整 performance tracing 或浏览器 Replay 的承诺。Convex 另有 Log Streams,可将函数执行和 console.* 日志发到 Axiom、Datadog、PostHog 或自定义 webhook,但当前列出的目的地不包括直接的 Sentry sink;需要自建 webhook 转换器时,要另外处理认证、脱敏、重试、事件模型和去重。Convex Log Streams
sentry 与 sentry-cli:前者是 v4,后者是旧 v3#
如果说的是开发、CI 中连接 Sentry SaaS 或 self-hosted 实例的命令行工具,答案是相反的:sentry 是新版 v4 CLI,sentry-cli 是旧版 v3 CLI。v4 是一次重写:npm 包从 @sentry/cli 改为 sentry,二进制也从 sentry-cli 改为 sentry。它仍会读取原来的 SENTRY_AUTH_TOKEN、SENTRY_ORG、SENTRY_PROJECT、SENTRY_URL 和 .sentryclirc,所以凭据和大部分项目配置可以沿用。Sentry CLI v3 → v4 迁移指南
| 目标 | v3(旧) | v4(新) |
|---|---|---|
| 安装包 / 可执行文件 | @sentry/cli / sentry-cli | sentry / sentry |
| 登录 | sentry-cli login | sentry auth login |
| 新建 release | sentry-cli releases new 1.0.0 | sentry release new 1.0.0 |
| 上传 source map | sentry-cli sourcemaps upload ./dist | sentry sourcemap upload ./dist(sourcemaps 仍是别名) |
| CI 认证 | token | token 仍可用;交互使用还可采用 OAuth device flow |
不要把已有 CI 的二进制名直接全局替换后就认为迁移完成。v4 将多数命令组从复数改为单数,且部分 flag(例如全局 --auth-token)改由环境变量提供;release deploy、source map 的部分参数也有语义变化。若现有流水线稳定,继续 pin 住 @sentry/cli / sentry-cli 是合理的;准备升级时,应逐条对照官方迁移表,并在 CI 中执行真实上传验证。官方也提供兼容 shim,使多数旧调用可在迁移期间转发给新版。
不要只用版本数字判断新旧#
迁移指南把新版称为 v4,但新版 sentry 可执行文件目前会显示 0.x 的版本号;例如 sentry --version 输出 0.41.0 并不表示它是旧版。判断依据应是二进制名与安装包:sentry / sentry npm 包是新版客户端,sentry-cli / @sentry/cli 才是旧版。升级排查时先确认实际解析到哪个命令,而不是仅按数字猜测:
command -v sentry
sentry --version
command -v sentry-cliCI 迁移时要验证什么#
旧版的 SENTRY_AUTH_TOKEN、SENTRY_ORG、SENTRY_PROJECT、SENTRY_URL 和 .sentryclirc 仍可复用;不要把 token 写进命令行或提交到仓库。相反,原来位于命令前的 --auth-token、self-hosted 使用的 --url、--header 已分别改用环境变量;--allow-failure 已移除。脚本若依赖旧版几乎总是 1 的退出码,或解析纯文本输出,也要重测:新版提供 --json,退出码按认证、输入、API 等错误类型分类。
先做不上传文件的连通性检查,再在 staging 或一次真实 production build 中验证 source map 和 release:
# 以下命令不创建 release,也不上传 source map
sentry --version
sentry auth status
sentry release list --json
sentry sourcemap upload --helprelease list 需要已有的组织、项目和认证配置;若失败,先修正 CI 注入的环境变量,而不是在脚本中回退到明文 token。实际构建验证通过、Sentry 中能看到正确 release 且故意制造的错误能还原到源码后,再卸载旧 sentry-cli。如果仓库代码直接 import 了 @sentry/cli 的 SentryCli 类,不能只替换命令:v4 改为 sentry 包的 createSentrySDK(),需要按官方迁移说明改写调用。
对本文的 Vite 场景,优先让 @sentry/vite-plugin 在 production build 中完成 source map 上传,通常无需手写任一 CLI 命令。只有自建 release/source-map 脚本、调试 source map 或管理 Sentry 资源时,才直接选择 CLI;无论选择哪一代,都要固定版本以保证 CI 可复现。
若你在self-hosted Sentry 服务容器内看到同名的 sentry,先用 command -v sentry 与 sentry --version 确认来源:那可能是服务端的 Python 管理命令,并不是这里的 v4 客户端 CLI。本文这节讨论的是开发者/CI 客户端;v4 客户端本身也可通过 SENTRY_URL 连到 self-hosted 实例。新版 CLI 安装与 self-hosted 配置
发布前清单#
- 同一产品的浏览器、Worker、Convex 后端放在同一个 Sentry Organization;按运行时拆 Project,而不是按环境拆 Project。
- 每个 Project 用自己的 DSN;浏览器只持有 public DSN,绝不持有
SENTRY_AUTH_TOKEN。 - 浏览器、Worker(以及有需要时 Convex 的发布记录)使用可追溯且一致的 release 约定;
environment使用稳定值。 - 只对本应用 API 设置
tracePropagationTargets;跨域时 CORS 允许sentry-trace与baggage。 - Logs 使用结构化字段,避免 token、cookie、原始 body 和过大的对象;先配置
beforeSend/beforeSendLog再放量。 - browser 与 Worker 的 source map 分别上传到正确 Project,并在生产 build 后验证一条还原后的栈。
- 显式测试浏览器错误、Worker 错误、SSR 渲染兜底、TanStack Server Function、结构化日志和跨端 trace。
参考资料(整理于 2026-08-11)#
- Sentry:Project 数量与边界
- Sentry:DSN、一个 Project 一个 DSN
- Sentry:Cloudflare Workers 上的 TanStack Start
- Sentry:TanStack Start 手动配置
- Sentry:React 的 TanStack Router tracing
- Sentry:JavaScript Logs
- Sentry CLI:从 v3(
sentry-cli)迁移到 v4(sentry) - Sentry CLI:安装、认证与配置
- TanStack Start:Cloudflare Workers Hosting
- TanStack Router:Vite 安装与 plugin 顺序
- Convex:Sentry Exception Reporting