多个 Sentry 实例

了解如何通过创建自己的客户端来管理多个 Sentry 实例。

通常情况下,不建议创建多个 Sentry 客户端,因为这可能导致意外行为。如果您使用微前端或类似架构,多路复用可能比使用多个客户端更好。更多信息请参阅 微前端 的最佳实践。

为了在多个 Sentry 实例之间避免冲突,您需要创建自己的 Client。这也有助于防止父应用程序的错误被跟踪,特别是在您的应用程序集成到父应用程序内部时。为确保不会与父应用程序冲突,您还应移除依赖全局状态的任何集成。

在以下示例中,我们使用 @sentry/browser 中的 BrowserClient,但这也适用于 @sentry/node 中的 NodeClient

Copied
import {
  BrowserClient,
  defaultStackParser,
  getDefaultIntegrations,
  makeFetchTransport,
  Scope,
} from "@sentry/browser";

// filter integrations that use the global variable
const integrations = getDefaultIntegrations({}).filter(
  (defaultIntegration) => {
    return !["BrowserApiErrors", "Breadcrumbs", "GlobalHandlers"].includes(
      defaultIntegration.name,
    );
  },
);

const client = new BrowserClient({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  transport: makeFetchTransport,
  stackParser: defaultStackParser,
  integrations: integrations,
});

const scope = new Scope();
scope.setClient(client);

client.init(); // initializing has to be done after setting the client on the scope

// You can capture exceptions manually for this client like this:
scope.captureException(new Error("example"));

现在您可以根据需要自定义作用域,而不会影响其他客户端。

集成是在 Client 上设置的。如果您需要处理多个客户端,必须确保集成处理设置正确。

我们不建议在浏览器扩展或类似场景中这样做。 如果您无法避免使用全局集成(例如在微前端应用程序中),以下是一个如何在多个客户端和多个作用域中运行全局集成的工作示例。

Copied
import * as Sentry from "@sentry/browser";

// Very happy integration that'll prepend and append very happy stick figure to the message
function happyIntegration() {
  return {
    name: "Happy",
    setupOnce() {
      Sentry.addEventProcessor((event) => {
        const self = Sentry.getClient().getIntegration(HappyIntegration);
        // Run the integration ONLY if it was installed on the current client
        if (self) {
          event.message = `\\o/ ${event.message} \\o/`;
        }
        return event;
      });
    },
  };
}

// filter integrations that use the global variable
const integrations = Sentry.getDefaultIntegrations({}).filter(
  (defaultIntegration) => {
    return !["BrowserApiErrors", "Breadcrumbs", "GlobalHandlers"].includes(
      defaultIntegration.name,
    );
  },
);

const client1 = new Sentry.BrowserClient({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  transport: Sentry.makeFetchTransport,
  stackParser: Sentry.defaultStackParser,
  integrations: [...integrations, happyIntegration()],
  beforeSend(event) {
    console.log("client 1", event);
    return null; // Returning `null` prevents the event from being sent
  },
});
const scope1 = new Sentry.Scope();
scope1.setClient(client1);

const client2 = new Sentry.BrowserClient({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", // Can be a different DSN
  transport: Sentry.makeFetchTransport,
  stackParser: Sentry.defaultStackParser,
  integrations: [...integrations, happyIntegration()],
  beforeSend(event) {
    console.log("client 2", event);
    return null; // Returning `null` prevents the event from being sent
  },
});
const scope2 = new Sentry.Scope();
scope2.setClient(client2);

scope1.captureMessage("a");
scope1.setTag("a", "b");

scope2.captureMessage("x");
scope2.setTag("c", "d");

默认情况下,Sentry.withScope() 会分叉当前作用域,并允许您添加仅在提供的回调内应用的数据。如果您想在多客户端设置中使用此功能,可以像这样使用 withScope

Copied
import * as Sentry from "@sentry/browser";

// Multiple clients setup as described above
const scopeA = new Sentry.Scope();
const clientA = new Sentry.BrowserClient(clientOptions);
scopeA.setClient(clientA);
clientA.init();

// Want to fork scopeA?
const scopeA2 = scopeA.clone();
Sentry.withScope(scopeA2, () => {
  // scopeA2 is active in this callback
  // it is still attached to clientA
  scopeA2.setTag("key", "value");
  scopeA2.captureMessage("message");
  // Any event captured inside of this callback will have scopeA2 applied to it
});