从 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+。

Copied
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|tssentry.edge.config.js|ts 模块,以初始化服务器端的 SDK。 instrumentation.ts 文件是 Next.js 的原生 API,称为 instrumentation hook

要开始使用 Next.js instrumentation hook,请按照以下步骤操作:

  1. 首先,通过在 next.config.js 中将 experimental.instrumentationHook 设置为 true 来启用 Next.js instrumentation hook。(从 Next.js 15 开始,此步骤不再需要)
next.config.js
Copied
module.exports = {
  experimental: {
    instrumentationHook: true, // Not required on Next.js 15+
  },
}
  1. 接下来,在项目的根目录(或 src 文件夹,如果您有该文件夹)中创建一个 instrumentation.ts|js 文件。

  2. 现在,从 instrumentation.ts|js 文件中导出一个 register 函数,并导入您的 sentry.server.config.js|tssentry.edge.config.js|ts 模块:

instrumentation.js
Copied
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');
  }
}

在 8.x 中,@sentry/nextjs 在服务器端已完全重写。它现在在内部使用 OpenTelemetry。您无需了解或理解 OpenTelemetry 即可使用 Sentry。我们会在内部设置 OpenTelemetry。如果您使用 OpenTelemetry 原生 API 来启动 span,Sentry 将自动捕获所有内容。

我们现在支持以下开箱即用的集成,无需任何配置:

  • httpIntegration: 自动仪器化 Node http 和 https 标准库
  • nativeNodeFetchIntegration: 自动仪器化顶级 fetch 和 undici
  • graphqlIntegration: 自动仪器化 GraphQL
  • mongoIntegration: 自动仪器化 MongoDB
  • mongooseIntegration: 自动仪器化 Mongoose
  • mysqlIntegration: 自动仪器化 MySQL
  • mysql2Integration: 自动仪器化 MySQL2
  • postgresIntegration: 自动仪器化 PostgreSQL

在 Sentry Next.js SDK 的 8.x 版本中,withSentryConfig 将不再接受 3 个参数。第二个参数(用于 Sentry Webpack 插件的选项)和第三个参数(用于 SDK 构建时配置的选项)现在应合并为一个:

next.config.js
Copied
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
Copied
 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 中进行了彻底改造。引入了新方法,并移除了 startTransactionspan.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
Copied
 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/*
Copied
-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
Copied
-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
Copied
-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
Copied
-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_BUILDisBuild 导出已被移除。这些导出没有替代品。

Next.js SDK 现在利用 Next.js 的 OpenTelemetry 仪器化进行跟踪。这意味着 SDK 将自动捕获 Next.js 应用程序的 OpenTelemetry 数据,而无需任何额外配置。

如果您之前使用了 @sentry/opentelemetry-node,则不再需要该依赖项,可以从项目中移除。要从使用 @sentry/opentelemetry-node 迁移到 Next.js SDK,请按照以下步骤操作:

  1. 确保您已根据 更新的 SDK 初始化 部分更新了 SDK 初始化。

  2. 从您的 Sentry.init 调用中移除 instrumenter: "otel",,以进行服务器端 SDK 初始化。

sentry.server.config.js
Copied
 import * as Sentry from '@sentry/nextjs';

 Sentry.init({
   dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
-  instrumenter: 'otel',
 });
  1. 移除项目中的 @sentry/opentelemetry-node 包和 instrumentation.node.js|ts 文件。确保 instrumentation.js|ts 不再导入 instrumentation.node.js|ts 文件。

enableAnrDetectionAnr 类导出已从 SDK 中移除。现在您可以使用 Sentry.anrIntegration 来启用 应用程序无响应检测

Copied
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 导入相关方法。此外,集成现在是函数式的,而不是基于类的。

Copied
-import { Replay } from '@sentry/replay';
-
 Sentry.init({
   dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
   integrations: [
-    new Replay(),
+    Sentry.replayIntegration(),
   ],
 });

Replay 选项 unblockunmask 现在默认值为 []。这意味着如果您想使用这些选项,您需要显式地设置它们,例如:

Copied
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”)所取代。目前,HubgetCurrentHub 仍然可用,但在下一个主要版本中将被移除。

有关如何替换现有 Hub API 使用的详细信息,请参阅 弃用 Hub

在 v7 中,集成是类,并可以像 integrations: [new Sentry.Replay()] 这样添加。在 v8 中,集成将不再是类,而是函数。使用类的方式以及从 Integrations.XXX 哈希中访问集成的方式已被弃用,取而代之的是使用新的函数式集成。例如,new Integrations.LinkedErrors() 变为 linkedErrorsIntegration()

有关集成及其替代方案的列表,请参阅 7.x 弃用文档

顶级 Sentry.configureScope 函数已被移除。相反,您应该使用 Sentry.getCurrentScope() 来访问和修改当前的作用域。

Copied
- Sentry.configureScope((scope) => {
-  scope.setTag("key", "value");
- });
+ Sentry.getCurrentScope().setTag("key", "value");

tracingOrigins 现已移除,取而代之的是 tracePropagationTargets 选项。tracePropagationTargets 选项应在 Sentry.init() 的选项中设置,或者在您创建自定义 Client 时在其选项中设置。

Copied
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 数组中。

Copied
// 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 不需要额外的配置。

Copied
// v8
Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
});

Sentry.metrics.increment("my_metric");

7.x 中,我们弃用了 Severity 枚举,转而使用 SeverityLevel 类型,这有助于减少打包大小。这一枚举在 8.x 中已被移除。您现在应直接使用 SeverityLevel 类型。

Copied
- import { Severity } from '@sentry/types';
+ import { SeverityLevel } from '@sentry/types';

- const level = Severity.error;
+ const level: SeverityLevel = "error";

8.x 中,我们移除了 spanStatusfromHttpCode 函数,转而使用 getSpanStatusFromHttpCode

Copied
- const spanStatus = spanStatusfromHttpCode(200);
+ const spanStatus = getSpanStatusFromHttpCode(200);

具有 framesToPop 属性的错误将从堆栈顶部移除指定数量的帧。这与 v7 中的行为不同,在 v7 中,framesToPop 属性用于从堆栈字符串中移除顶部 n 行。

8.x 中,我们不再从 SDK 包中导出 Span 类。内部现在称这个类为 SentrySpan,并且不再打算让用户直接使用它。

Transport 接口上的 send 方法现在总是要求在 promise 中返回一个 TransportMakeRequestResponse。这意味着不再允许 void 返回类型。

Copied
// v7
 interface Transport {
-  send(event: Event): Promise<void | TransportMakeRequestResponse>;
+  send(event: Event): Promise<TransportMakeRequestResponse>;
 }

extraErrorDataIntegration 集成现在默认会查看 error.cause

transactionContext 不再传递给 tracesSampler 回调函数,取而代之的是,回调函数将直接接收 nameattributes。请注意,attributes 仅包含在创建 span 时的属性,某些属性可能只会在 span 生命周期的后期设置(因此在采样期间不可用)。

如果调用了 Sentry.init()getClient() 现在始终返回一个客户端。对于可能用于检查 Sentry 是否实际初始化的情况,使用 getClient() 将不再起作用。相反,您应该使用新的 Sentry.isInitialized() 工具来检查这一点。

8.x 中,我们移除了 addGlobalEventProcessor 函数,转而使用 addEventProcessor

Copied
- 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 文档

Copied
// 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}`)
    })
})