从 7.x 迁移到 8.x
了解如何从 Sentry JavaScript SDK 7.x 迁移到 8.x
8.x 版本的主要目标是改进我们的性能监控 API、集成 API 和 ESM 支持。此版本包含破坏性更改,因为我们移除了已弃用的 API,重构了 npm 包内容,并引入了对 OpenTelemetry 的新依赖。
在升级到 8.x
SDK 之前,我们建议先升级到 7.x
的最新版本。要修复 7.x
中的大部分弃用问题,您可以使用 @sentry/migr8
codemod 自动更新您的 SDK 使用方式。@sentry/migr8
需要 Node 18+。
npx @sentry/migr8@latest
我们的迁移工具将允许您选择要运行的更新,并自动更新您的代码。在某些情况下,我们无法自动为您更改代码。这些情况将被标记为 TODO(sentry)
注释。请确保在运行 @sentry/migr8
后审查所有代码更改!有关弃用的更多详细信息,请参阅我们关于 7.x 中的弃用 的文档。尽管有 @sentry/migr8
,我们仍然建议阅读迁移指南,因为 @sentry/migr8
并不涵盖所有需要的迁移更改。
8.x
简化了 Sentry Next.js SDK 的初始化,并利用了 Next.js 的 OpenTelemetry 仪器化进行跟踪。
我们建议您阅读所有 重要更改,因为这些更改影响所有 SDK 用户。下面链接的 其他更改 仅影响具有更自定义 instrumentation 的用户。还有一个 故障排除 部分,涵盖了常见问题。
我们还在 GitHub 上提供了一份 详细的迁移指南,其中包含了所有更改的综合列表以及 SDK 的源代码。
Sentry Next.js SDK 8.x
支持:
- Next.js 版本
13.2.0
或更高版本 - Webpack
5.0.0
或更高版本 - Node
14.18.0
或更高版本
如果您需要支持更早版本的 Node.js 或 Next.js,请使用 Sentry Next.js SDK 7.x
。
SDK 现在需要 ES2018 兼容性以及对 globalThis
的支持。最低支持的浏览器版本为:
- Chrome 71
- Edge 79
- Safari 12.1,iOS Safari 12.2
- Firefox 65
- Opera 58
- Samsung Internet 10
对于 IE11 支持,请使用 Babel 或类似工具将代码编译为 ES5,并添加所需的 polyfills。
在 8.x
中,Next.js SDK 需要一个额外的 instrumentation.ts
文件来执行 sentry.server.config.js|ts
和 sentry.edge.config.js|ts
模块,以初始化服务器端的 SDK。 instrumentation.ts
文件是 Next.js 的原生 API,称为 instrumentation hook。
要开始使用 Next.js instrumentation hook,请按照以下步骤操作:
- 首先,通过在
next.config.js
中将experimental.instrumentationHook
设置为true
来启用 Next.js instrumentation hook。(从 Next.js 15 开始,此步骤不再需要)
next.config.js
module.exports = {
experimental: {
instrumentationHook: true, // Not required on Next.js 15+
},
}
接下来,在项目的根目录(或
src
文件夹,如果您有该文件夹)中创建一个instrumentation.ts|js
文件。现在,从
instrumentation.ts|js
文件中导出一个register
函数,并导入您的sentry.server.config.js|ts
和sentry.edge.config.js|ts
模块:
instrumentation.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');
}
}
如果您使用的是 Next.js 自定义服务器,instrumentation.ts|js
钩子不会被 Next.js 调用,因此 SDK 仪器化将无法按预期工作。请参阅 故障排除部分 以获取更多信息。
在 8.x 中,@sentry/nextjs
在服务器端已完全重写。它现在在内部使用 OpenTelemetry。您无需了解或理解 OpenTelemetry 即可使用 Sentry。我们会在内部设置 OpenTelemetry。如果您使用 OpenTelemetry 原生 API 来启动 span,Sentry 将自动捕获所有内容。
我们现在支持以下开箱即用的集成,无需任何配置:
httpIntegration
: 自动仪器化 Node http 和 https 标准库nativeNodeFetchIntegration
: 自动仪器化顶级 fetch 和 undicigraphqlIntegration
: 自动仪器化 GraphQLmongoIntegration
: 自动仪器化 MongoDBmongooseIntegration
: 自动仪器化 MongoosemysqlIntegration
: 自动仪器化 MySQLmysql2Integration
: 自动仪器化 MySQL2postgresIntegration
: 自动仪器化 PostgreSQL
在 Sentry Next.js SDK 的 8.x 版本中,withSentryConfig
将不再接受 3 个参数。第二个参数(用于 Sentry Webpack 插件的选项)和第三个参数(用于 SDK 构建时配置的选项)现在应合并为一个:
next.config.js
const nextConfig = {
// Your Next.js options...
};
-module.exports = withSentryConfig(
- nextConfig,
- {
- // Your Sentry Webpack Plugin Options...
- },
- {
- // Your Sentry SDK options...
- },
-);
+module.exports = withSentryConfig(nextConfig, {
+ // Your Sentry Webpack Plugin Options...
+ // AND your Sentry SDK options...
+});
作为此更改的一部分,SDK 将不再支持通过 sentry
属性将 Next.js 选项传递给 withSentryConfig
。请使用 withSentryConfig
的第二个参数来配置 SDK。
next.config.js
const nextConfig = {
// Your Next.js options...
-
- sentry: {
- // Your Sentry SDK options...
- },
};
module.exports = withSentryConfig(nextConfig, {
// Your Sentry Webpack Plugin Options...
+ // AND your Sentry SDK options...
});
追踪的自定义 instrumentation API 在 8.x
中进行了彻底改造。引入了新方法,并移除了 startTransaction
和 span.startChild
。更多信息请参阅 新的追踪 API 文档。
在内部,Next.js SDK 使用 Sentry Webpack Plugin 来上传 source map 并自动将发布版本关联到您的事件。在 8.x
中,SDK 现在使用 Sentry Webpack Plugin 的 2.x
版本,带来了许多改进和 bug 修复。Next.js SDK 现在使用 Debug IDs 进行 source map 上传。
以下先前弃用的 API 已从 @sentry/nextjs
包中移除:
nextRouterInstrumentation
已被browserTracingIntegration
取代。
sentry.client.config.js
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
integrations: [
- new Sentry.Integrations.BrowserTracing({
- routingInstrumentation: Sentry.nextRouterInstrumentation
- }),
+ Sentry.browserTracingIntegration(),
]
});
withSentryApi
已被wrapApiHandlerWithSentry
取代。
pages/api/*
-import { withSentryApi } from "@sentry/nextjs";
+import { wrapApiHandlerWithSentry } from "@sentry/nextjs";
const handler = (req, res) => {
res.status(200).json({ name: "John Doe" });
};
-export default withSentryApi(handler, "/api/myRoute");
+export default wrapApiHandlerWithSentry(handler, "/api/myRoute");
withSentryGetServerSideProps
已被wrapGetServerSidePropsWithSentry
取代。
pages/index.js
-import { withSentryGetServerSideProps } from "@sentry/nextjs";
+import { wrapGetServerSidePropsWithSentry } from "@sentry/nextjs";
export async function _getServerSideProps() {
// Fetch data from external API
}
-export const getServerSideProps = withSentryGetServerSideProps(_getServerSideProps);
+export const getServerSideProps = wrapGetServerSidePropsWithSentry(_getServerSideProps);
withSentryGetStaticProps
已被wrapGetStaticPropsWithSentry
取代。
pages/index.js
-import { withSentryGetStaticProps } from "@sentry/nextjs";
+import { wrapGetStaticPropsWithSentry } from "@sentry/nextjs";
export async function _getStaticProps() {
// Fetch data from external API
}
-export const getStaticProps = withSentryGetStaticProps(_getServerSideProps);
+export const getStaticProps = wrapGetStaticPropsWithSentry(_getServerSideProps);
withSentryServerSideGetInitialProps
已被wrapGetInitialPropsWithSentry
取代。
pages/index.js
-import { withSentryServerSideGetInitialProps } from "@sentry/nextjs";
+import { wrapGetInitialPropsWithSentry } from "@sentry/nextjs";
async function getInitialProps() {
// Fetch data from external API
return { data }
}
-Page.getInitialProps = withSentryServerSideGetInitialProps(getInitialProps);
+Page.getInitialProps = wrapGetInitialPropsWithSentry(getInitialProps);
export default function Page({ data }) {
return data
}
类似于上述更改,以下 API 已被移除:
withSentryServerSideAppGetInitialProps
已被wrapAppGetInitialPropsWithSentry
取代。withSentryServerSideDocumentGetInitialProps
已被wrapDocumentGetInitialPropsWithSentry
取代。withSentryServerSideErrorGetInitialProps
已被wrapErrorGetInitialPropsWithSentry
取代。
IS_BUILD
和 isBuild
导出已被移除。这些导出没有替代品。
Next.js SDK 现在利用 Next.js 的 OpenTelemetry 仪器化进行跟踪。这意味着 SDK 将自动捕获 Next.js 应用程序的 OpenTelemetry 数据,而无需任何额外配置。
如果您之前使用了 @sentry/opentelemetry-node
,则不再需要该依赖项,可以从项目中移除。要从使用 @sentry/opentelemetry-node
迁移到 Next.js SDK,请按照以下步骤操作:
确保您已根据 更新的 SDK 初始化 部分更新了 SDK 初始化。
从您的
Sentry.init
调用中移除instrumenter: "otel",
,以进行服务器端 SDK 初始化。
sentry.server.config.js
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
- instrumenter: 'otel',
});
- 移除项目中的
@sentry/opentelemetry-node
包和instrumentation.node.js|ts
文件。确保instrumentation.js|ts
不再导入instrumentation.node.js|ts
文件。
enableAnrDetection
和 Anr
类导出已从 SDK 中移除。现在您可以使用 Sentry.anrIntegration
来启用 应用程序无响应检测。
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.anrIntegration({ captureStackTrace: true })
],
});
之前,即使注册了其他 onUncaughtException
处理程序(这些处理程序会阻止进程退出),SDK 默认情况下仍然会退出进程。您可以通过在 onUncaughtExceptionIntegration
选项中设置 exitEvenIfOtherHandlersAreRegistered: false
来选择退出这种行为。到目前为止,此选项的默认值为 true
。
从现在起,默认值 exitEvenIfOtherHandlersAreRegistered
将变为 false
,这意味着如果您注册了其他 onUncaughtException
处理程序,SDK 将不会退出您的进程。
deepReadDirSync
方法已从 SDK 的导出中移除,没有替代的 API。
Sentry tRPC 中间件已从 Sentry.Handlers.trpcMiddleware()
移动到 Sentry.trpcMiddleware()
。
SDK 不再默认过滤掉健康检查事务。相反,这些事务会被发送到 Sentry,但仍然会默认由 Sentry 后端丢弃。您可以在 Sentry 项目设置中禁用丢弃它们。如果您仍想在 SDK 内丢弃特定事务,可以使用 ignoreTransactions
SDK 选项。
@sentry/replay
包不再需要。相反,您可以直接从 SDK 导入相关方法。此外,集成现在是函数式的,而不是基于类的。
-import { Replay } from '@sentry/replay';
-
Sentry.init({
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
integrations: [
- new Replay(),
+ Sentry.replayIntegration(),
],
});
Replay 选项 unblock
和 unmask
现在默认值为 []
。这意味着如果您想使用这些选项,您需要显式地设置它们,例如:
Sentry.init({
integrations: [
Sentry.replayIntegration({
unblock: [".sentry-unblock, [data-sentry-unblock]"],
unmask: [".sentry-unmask, [data-sentry-unmask]"],
}),
],
});
通过 makeXHRTransport
的 xhr 传输已被移除。现在仅提供 makeFetchTransport
。这意味着 Sentry SDK 需要环境中支持 fetch
API。
Offline
集成已被移除,取而代之的是 离线传输包装器。
Sentry.wrap
导出已被移除,没有替代的 API。
我们更新了当未定义 tracePropagationTargets
选项时 SDK 的行为。作为提醒,您可以提供一个字符串或正则表达式的列表,这些将与 URL 匹配,以告诉 SDK 应该向哪些传出请求附加追踪 HTTP 头。这些追踪头用于分布式追踪。
以前,在浏览器中,当未定义 tracePropagationTargets
时,默认值为 ['localhost', /^\/(?!\/)/]
。这意味着所有目标 URL 包含 "localhost" 或以 /
开头的请求都会附带追踪头。这个默认值是为了防止浏览器应用程序中的 CORS 错误。然而,这个默认值存在一些问题。
从现在起,当未设置 tracePropagationTargets
选项时,追踪头将仅附加到同源的所有传出请求。例如,如果您在 https://example.com/
上,并发送请求到 https://example.com/api
,该请求将被追踪(即会附带追踪头)。发送到 https://api.example.com/
的请求不会被追踪,因为它属于不同的源。同样适用于所有运行在 localhost
上的应用程序。
当您提供了 tracePropagationTargets
选项时,所有定义的条目现在将与传出请求的完整 URL 进行匹配。以前,它只与您调用请求 API 时提供的路径进行匹配。例如,如果您发起一个类似 fetch("/api/posts")
的请求,提供的 tracePropagationTargets
之前只会与 "/api/posts"
进行比较。
到目前为止,Hub
一直是 Sentry SDK API 中非常重要的一部分。Hubs 是 SDK 的“并发单元”,用于在不同线程之间跟踪数据,并将数据作用域限定在代码的某些部分。由于它过于复杂且容易让高级用户感到困惑,它将被一组新的 API(即“新的 Scope API”)所取代。目前,Hub
和 getCurrentHub
仍然可用,但在下一个主要版本中将被移除。
有关如何替换现有 Hub API 使用的详细信息,请参阅 弃用 Hub。
在 v7 中,集成是类,并可以像 integrations: [new Sentry.Replay()]
这样添加。在 v8 中,集成将不再是类,而是函数。使用类的方式以及从 Integrations.XXX
哈希中访问集成的方式已被弃用,取而代之的是使用新的函数式集成。例如,new Integrations.LinkedErrors()
变为 linkedErrorsIntegration()
。
有关集成及其替代方案的列表,请参阅 7.x 弃用文档。
顶级 Sentry.configureScope
函数已被移除。相反,您应该使用 Sentry.getCurrentScope()
来访问和修改当前的作用域。
- Sentry.configureScope((scope) => {
- scope.setTag("key", "value");
- });
+ Sentry.getCurrentScope().setTag("key", "value");
tracingOrigins
现已移除,取而代之的是 tracePropagationTargets
选项。tracePropagationTargets
选项应在 Sentry.init()
的选项中设置,或者在您创建自定义 Client
时在其选项中设置。
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [Sentry.browserTracingIntegration()],
tracePropagationTargets: ["localhost", "example.com"],
});
在 7.x
中,您需要通过将 _experiments
选项设置为 { metricsAggregator: true }
来启用 metrics 聚合器。此外,在浏览器环境中,您还需要将 metricsAggregatorIntegration
添加到 integrations
数组中。
// v7 - Server (Node/Deno/Bun)
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
_experiments: {
metricsAggregator: true,
},
});
// v7 - Browser
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [Sentry.metricsAggregatorIntegration()],
});
Sentry.metrics.increment("my_metric");
在 8.x
中,使用 metrics API 不需要额外的配置。
// v8
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
});
Sentry.metrics.increment("my_metric");
在 7.x
中,我们弃用了 Severity
枚举,转而使用 SeverityLevel
类型,这有助于减少打包大小。这一枚举在 8.x
中已被移除。您现在应直接使用 SeverityLevel
类型。
- import { Severity } from '@sentry/types';
+ import { SeverityLevel } from '@sentry/types';
- const level = Severity.error;
+ const level: SeverityLevel = "error";
在 8.x
中,我们移除了 spanStatusfromHttpCode
函数,转而使用 getSpanStatusFromHttpCode
。
- const spanStatus = spanStatusfromHttpCode(200);
+ const spanStatus = getSpanStatusFromHttpCode(200);
具有 framesToPop
属性的错误将从堆栈顶部移除指定数量的帧。这与 v7 中的行为不同,在 v7 中,framesToPop
属性用于从堆栈字符串中移除顶部 n 行。
在 8.x
中,我们不再从 SDK 包中导出 Span
类。内部现在称这个类为 SentrySpan
,并且不再打算让用户直接使用它。
Transport
接口上的 send
方法现在总是要求在 promise 中返回一个 TransportMakeRequestResponse
。这意味着不再允许 void
返回类型。
// v7
interface Transport {
- send(event: Event): Promise<void | TransportMakeRequestResponse>;
+ send(event: Event): Promise<TransportMakeRequestResponse>;
}
extraErrorDataIntegration
集成现在默认会查看 error.cause
。
transactionContext
不再传递给 tracesSampler
回调函数,取而代之的是,回调函数将直接接收 name
和 attributes
。请注意,attributes
仅包含在创建 span 时的属性,某些属性可能只会在 span 生命周期的后期设置(因此在采样期间不可用)。
如果调用了 Sentry.init()
,getClient()
现在始终返回一个客户端。对于可能用于检查 Sentry 是否实际初始化的情况,使用 getClient()
将不再起作用。相反,您应该使用新的 Sentry.isInitialized()
工具来检查这一点。
在 8.x
中,我们移除了 addGlobalEventProcessor
函数,转而使用 addEventProcessor
。
- Sentry.addGlobalEventProcessor((event) => {
+ Sentry.getGlobalScope().addEventProcessor((event) => {
delete event.extra;
return event;
});
@sentry/integrations
已被移除,将不再发布。我们将可插拔的集成从单独的包 (@sentry/integrations
) 移动到了 @sentry/nextjs
。此外,这些集成现在是函数而不是类。
从 @sentry/nextjs
导出的客户端初始化集成:
httpClientIntegration
(HTTPClient
)contextLinesIntegration
(ContextLines
)reportingObserverIntegration
(ReportingObserver
)
从 @sentry/nextjs
导出的客户端和服务器端初始化集成:
captureConsoleIntegration
(CaptureConsole
)debugIntegration
(Debug
)extraErrorDataIntegration
(ExtraErrorData
)rewriteFramesIntegration
(RewriteFrames
)sessionTimingIntegration
(SessionTiming
)dedupeIntegration
(Dedupe
) - 注意:默认启用,不可插拔
Transaction
集成已从 @sentry/integrations
中移除。没有替代的 API。
Next.js SDK 的 8.x
版本强制使用 instrumentation.ts
文件,因为它是一种更灵活和强大的初始化方式,并允许我们使用 Next.js 内置的钩子和 OpenTelemetry 仪器化。此外,这有助于 SDK 更好地兼容 Turbopack,而 Next.js SDK 7.x
不支持 Turbopack。Next.js 团队建议使用 instrumentation.ts
文件进行 SDK 初始化,我们正在与他们密切合作,以确保 SDK 与 Next.js 无缝兼容。
如果您使用的是 Next.js 自定义服务器,instrumentation.ts|js
钩子不会被 Next.js 调用,因此您需要手动在服务器代码中调用它。建议在应用程序生命周期的早期阶段进行调用。
以下是一个示例,展示如何将 Sentry 初始化代码添加到自定义服务器示例中,参考 Next.js 文档:
// make sure that Sentry is imported and initialized before any other imports.
+ const Sentry = require('@sentry/nextjs');
+
+ Sentry.init({
+ dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
+ // Your Node.js Sentry configuration...
+ })
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer(async (req, res) => {
// server code
})
.once('error', (err) => {
// error code
})
.listen(port, () => {
console.log(`> Ready on http://${hostname}:${port}`)
})
})