-
Notifications
You must be signed in to change notification settings - Fork 45
feat(monitoring): 接入 Sentry 错误监控 #296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| /** | ||
| * Next.js 15+ 约定的启动 hook:每个 runtime 启动时各自拉对应 Sentry 配置, | ||
| * 避免在 edge runtime 错误加载 Node-only 代码。 | ||
| * | ||
| * onRequestError 暴露给 Next.js 捕获服务端组件/路由层面的未捕获错误。 | ||
| */ | ||
| import * as Sentry from "@sentry/nextjs"; | ||
|
|
||
| export async function register() { | ||
| if (process.env.NEXT_RUNTIME === "nodejs") { | ||
| await import("./sentry.server.config"); | ||
| } | ||
| if (process.env.NEXT_RUNTIME === "edge") { | ||
| await import("./sentry.edge.config"); | ||
| } | ||
| } | ||
|
|
||
| export const onRequestError = Sentry.captureRequestError; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| // next.config.mjs | ||||||||||||||||||||||||||||||||||||||||||||||
| import { createMDX } from "fumadocs-mdx/next"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import createNextIntlPlugin from "next-intl/plugin"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { withSentryConfig } from "@sentry/nextjs"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||
| * IMPORTANT: remarkImage 配置已移至 source.config.ts 统一管理 | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -131,4 +132,26 @@ const config = { | |||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export default withNextIntl(withMDX(config)); | ||||||||||||||||||||||||||||||||||||||||||||||
| const finalConfig = withNextIntl(withMDX(config)); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // Sentry 包裹:webpack 插件需要看到最终的 Next 配置才能上传 source map。 | ||||||||||||||||||||||||||||||||||||||||||||||
| // silent: !CI 让本地构建不刷日志,只在 Vercel CI 构建时打印。 | ||||||||||||||||||||||||||||||||||||||||||||||
| // widenClientFileUpload 扩大 source map 扫描范围,保证前端错误堆栈能解出来。 | ||||||||||||||||||||||||||||||||||||||||||||||
| // disableLogger 树摇掉 Sentry 自带 logger,减小 bundle 体积。 | ||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||
| // 守门条件:只有在存在 SENTRY_AUTH_TOKEN 时才启用 withSentryConfig。 | ||||||||||||||||||||||||||||||||||||||||||||||
| // 贡献者 clone 仓库后没配 Sentry env 也能直接 `pnpm build` / `pnpm dev`, | ||||||||||||||||||||||||||||||||||||||||||||||
| // 不会因为 webpack 插件缺凭据而构建失败。生产 Vercel 那边 env 齐全,正常上报。 | ||||||||||||||||||||||||||||||||||||||||||||||
| const enableSentry = Boolean(process.env.SENTRY_AUTH_TOKEN); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export default enableSentry | ||||||||||||||||||||||||||||||||||||||||||||||
| ? withSentryConfig(finalConfig, { | ||||||||||||||||||||||||||||||||||||||||||||||
| org: process.env.SENTRY_ORG || "involutionhell", | ||||||||||||||||||||||||||||||||||||||||||||||
| project: process.env.SENTRY_PROJECT || "sentry-bole-notebook", | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+142
to
+150
|
||||||||||||||||||||||||||||||||||||||||||||||
| // 守门条件:只有在存在 SENTRY_AUTH_TOKEN 时才启用 withSentryConfig。 | |
| // 贡献者 clone 仓库后没配 Sentry env 也能直接 `pnpm build` / `pnpm dev`, | |
| // 不会因为 webpack 插件缺凭据而构建失败。生产 Vercel 那边 env 齐全,正常上报。 | |
| const enableSentry = Boolean(process.env.SENTRY_AUTH_TOKEN); | |
| export default enableSentry | |
| ? withSentryConfig(finalConfig, { | |
| org: process.env.SENTRY_ORG || "involutionhell", | |
| project: process.env.SENTRY_PROJECT || "sentry-bole-notebook", | |
| // 守门条件:只有在存在完整的 Sentry env 时才启用 withSentryConfig。 | |
| // 贡献者 clone 仓库后没配 Sentry env 也能直接 `pnpm build` / `pnpm dev`, | |
| // 不会因为 webpack 插件缺凭据而构建失败。生产 Vercel 那边 env 齐全,正常上报。 | |
| const enableSentry = Boolean( | |
| process.env.SENTRY_AUTH_TOKEN && | |
| process.env.SENTRY_ORG && | |
| process.env.SENTRY_PROJECT, | |
| ); | |
| export default enableSentry | |
| ? withSentryConfig(finalConfig, { | |
| org: process.env.SENTRY_ORG, | |
| project: process.env.SENTRY_PROJECT, |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,20 @@ | ||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Sentry 浏览器端初始化。 | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * 免费 tier 策略(Developer plan,5K errors/月 + 10K perf units/月): | ||||||||||||||||||||||||
| * - 只在 production 启用,避免本地 dev/preview 污染配额 | ||||||||||||||||||||||||
| * - tracesSampleRate 0.1:10% 的页面 transaction 采样足够看性能趋势 | ||||||||||||||||||||||||
| * - 关闭 Session Replay:它是另外的独立配额(小),开了容易炸 | ||||||||||||||||||||||||
| * - 不启用 profiling(需要付费) | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| import * as Sentry from "@sentry/nextjs"; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Sentry.init({ | ||||||||||||||||||||||||
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | ||||||||||||||||||||||||
| enabled: process.env.NODE_ENV === "production", | ||||||||||||||||||||||||
|
Comment on lines
+12
to
+14
|
||||||||||||||||||||||||
| Sentry.init({ | |
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | |
| enabled: process.env.NODE_ENV === "production", | |
| const isSentryEnabled = | |
| process.env.NODE_ENV === "production" && | |
| process.env.VERCEL_ENV === "production" && | |
| !!process.env.NEXT_PUBLIC_SENTRY_DSN; | |
| Sentry.init({ | |
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | |
| enabled: isSentryEnabled, |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,12 @@ | ||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Sentry Edge runtime 初始化(Middleware / Edge routes)。 | ||||||||||||||||||||||||||||||||||||
| * 当前项目未使用 edge runtime,保留配置以便未来迁移时无需补齐。 | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| import * as Sentry from "@sentry/nextjs"; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Sentry.init({ | ||||||||||||||||||||||||||||||||||||
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | ||||||||||||||||||||||||||||||||||||
| enabled: process.env.NODE_ENV === "production", | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+9
|
||||||||||||||||||||||||||||||||||||
| * 当前项目未使用 edge runtime,保留配置以便未来迁移时无需补齐。 | |
| */ | |
| import * as Sentry from "@sentry/nextjs"; | |
| Sentry.init({ | |
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | |
| enabled: process.env.NODE_ENV === "production", | |
| * 当前配置用于 Next.js 的 middleware 及其他 Edge runtime 入口。 | |
| * 仅在 production 且已配置 NEXT_PUBLIC_SENTRY_DSN 时启用,避免本地/未配置环境误报。 | |
| */ | |
| import * as Sentry from "@sentry/nextjs"; | |
| Sentry.init({ | |
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | |
| enabled: | |
| process.env.NODE_ENV === "production" && | |
| Boolean(process.env.NEXT_PUBLIC_SENTRY_DSN), |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,12 @@ | ||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Sentry Node.js runtime 初始化(Next.js API routes / Server Components / RSC)。 | ||||||||||||||||||||||||||
| * 与 client 同策略:仅 production 启用,traces 10%,无 replay/profiling。 | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| import * as Sentry from "@sentry/nextjs"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Sentry.init({ | ||||||||||||||||||||||||||
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | ||||||||||||||||||||||||||
| enabled: process.env.NODE_ENV === "production", | ||||||||||||||||||||||||||
|
Comment on lines
+7
to
+9
|
||||||||||||||||||||||||||
| Sentry.init({ | |
| dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, | |
| enabled: process.env.NODE_ENV === "production", | |
| const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN; | |
| const isProductionDeployment = | |
| process.env.VERCEL_ENV != null | |
| ? process.env.VERCEL_ENV === "production" | |
| : process.env.NODE_ENV === "production"; | |
| Sentry.init({ | |
| dsn, | |
| enabled: Boolean(dsn) && isProductionDeployment, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.env.sample 里写“本地 dev/preview 不会产生事件”,但当前实现只用
NODE_ENV === "production"控制;在 Vercel Preview 部署中NODE_ENV同样是 production,实际上仍可能上报事件并消耗配额。建议在示例说明里补充真实条件(例如结合VERCEL_ENV),或同步调整代码使其与文档一致。