Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)

244 阅读13分钟

系列

  1. Sentry-Go SDK 中文实践指南
  2. 一起来刷 Sentry For Go 官方文档之 Enriching Events
  3. Snuba:Sentry 新的搜索基础设施(基于 ClickHouse 之上)
  4. Sentry 10 K8S 云原生架构探索,Vue App 1 分钟快速接入
  5. Sentry(v20.12.1) K8S 云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能+高可用+可扩展+可伸缩集群部署
  6. Sentry(v20.12.1) K8S 云原生架构探索,Sentry JavaScript SDK 三种安装加载方式
  7. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT SDK 配置详解
  8. Sentry(v20.12.1) K8S 云原生架构探索, SENTRY FOR JAVASCRIPT 手动捕获事件基本用法
  9. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT Source Maps详解
  10. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT 故障排除
  11. Sentry(v20.12.1) K8S 云原生架构探索,1分钟上手 JavaScript 性能监控
  12. Sentry(v20.12.1) K8S 云原生架构探索,JavaScript 性能监控之管理 Transactions
  13. Sentry(v20.12.1) K8S 云原生架构探索,JavaScript 性能监控之采样 Transactions

Add Context

自定义上下文允许您将任意数据附加到事件。通常,此上下文在其生命周期中捕获的任何 issue 之间都是共享的。您无法搜索这些,但可以在 issue 页面上查看它们:

Structured Context

附加自定义 data 的最佳实践是通过结构化上下文。上下文必须始终是一个 dictionary 或 map,它的值可以是任意的。使用 setContext 并给 context 一个唯一的名称:

Sentry.setContext("character", {
  name: "Mighty Fighter",
  age: 19,
  attack_type: "melee",
});

Size Limitations

发送上下文时,请考虑有效负载大小限制。 Sentry 不建议在上下文中发送整个应用程序状态和大数据 blob。如果超过最大有效负载大小,Sentry 将响应 413 Payload Too Large,并拒绝该事件。使用 keepalive: true 时,该请求可能会永远保持待处理状态。

Passing Context Directly

从我们的 JavaScript SDK 5.16.0 版本开始,可以将某些上下文数据直接提供给 captureExceptioncaptureMessage 调用。提供的数据将与当前范围内已经存储的数据合并,除非使用回调方法明确将其清除。

此功能有三种不同的变体形式:

  1. 包含可更新属性的普通对象
  2. 我们将从中提取属性的 Scope 实例
  3. 回调函数,它将接收当前 scope 作为参数并允许修改

我们允许传递以下上下文 keys:tags, extra, contexts, user, level, fingerprint

Example Usages

Sentry.captureException(new Error("something went wrong"), {
  tags: {
    section: "articles",
  },
});

显式清除已经存储在 scope 中的内容:

Sentry.captureException(new Error("clean as never"), scope => {
  scope.clear();
  scope.setTag("clean", "slate");
  return scope;
});

使用 Scope 实例传递数据(其属性仍将与全局 scope 合并):

const scope = new Sentry.Scope();
scope.setTag("section", "articles");
Sentry.captureException(new Error("something went wrong"), scope);

使用 Scope 实例传递数据并忽略全局配置的 Scope 属性:

const scope = new Sentry.Scope();
scope.setTag("section", "articles");
Sentry.captureException(new Error("something went wrong"), () => scope);

Clearing Context

Context 保留在当前 scope 内,因此在每个操作(请求等)结束时将其清除。您还可以 push 和 pop 自己的作用域,以将上下文数据应用于特定的代码块或函数。

Sentry 支持两种不同的 scope 来设置上下文:

  1. global scope,Sentry 在操作结束时不会丢弃
  2. 用户创建的 scope

这将在以后的所有事件中更改:

这将在以后的所有事件中更改:

仅针对在 withScope 回调中捕获的错误,将更改此状态,然后自动将其恢复为先前的值:

Sentry.withScope(function(scope) {
  scope.setUser(someUser);
  Sentry.captureException(error);
});

如果你想从作用域中(Scope)删除全局配置的数据,你可以调用:

Sentry.configureScope(scope => scope.clear());

Additional Data

除了结构化上下文(structured contexts),Sentry 还支持通过 setExtra 添加非结构化 "Additional Data"。Additional Data 已经废弃,而应使用结构化上下文,并应尽可能避免使用。

Identify Users

用户包含一些关键信息,这些信息构成了 Sentry 中的唯一身份。每个选项都是可选的,但必须存在一个选项才能使Sentry SDK 捕获用户:

id: 您的用户内部标识符。

username: 用户名。通常用作比内部 ID 更好的标签。

email: username 的替代或补充。Sentry 知道电子邮件地址,并且可以显示诸如 Gravatars 之类的内容并解锁消息传递功能。

ip_address: 用户的 IP 地址。如果用户未经身份验证,Sentry 将 IP 地址用作用户的唯一标识符。Sentry 将尝试从 HTTP 请求数据中提取此信息(如果有)。设置为 "{{auto}}",以使 Sentry 从 connection 中推断 IP 地址。

此外,您可以提供保留名称之外的任意 key/value 对,Sentry SDK 会将这些 key/value 对与 user 一起存储。

识别用户:

Sentry.setUser({ email: "john.doe@example.com" });

您还可以清除当前设置的 user:

Sentry.configureScope(scope => scope.setUser(null));

Set Transaction Name

当前 transaction 名称用于对 Performance 产品中的 transactions 进行分组,并用 failure 点注释错误事件。

transaction 名称可以引用当前的 Web 应用程序路由或正在执行的当前 task。 例如:

  • GET /api/{version}/users/
  • UserListView
  • myapp.tasks.renew_all_subscriptions

理想情况下,transaction 名称不包含诸如用户 ID 之类的变量值,但具有较低的基数,同时仍可以唯一地标识您所关心的代码。

我们的许多框架集成已经设置了 transaction 名称。自己设定:

Sentry.configureScope(scope => scope.setTransactionName("UserListView"));

这将覆盖当前正在运行的 transaction 的名称。

Customize Tags

Tags 是既可索引又可搜索的 key/value 字符串对。Tags 具有强大的 UI 功能,例如过滤器(filters)和标签分布图(tag-distribution maps)。Tags 还可以帮助您快速访问相关事件,并查看一组事件的标签分布(tag distribution)。Tags 的常见用法包括主机名(hostname),平台版本(platform version)和用户语言(user language)。

我们将自动为一个事件的所有 tags 建立索引,以及 Sentry 看到标签的频率和最后一次。我们还将跟踪不同 tags 的数量,并可以帮助您确定各种 issues 的热点。

定义 tags 很容易,并将它们绑定到 current scope,确保 scope 内的所有未来事件都包含相同的标签:

Sentry.setTag("page_locale", "de-at");

某些 tags 由 Sentry 自动设置。强烈建议您不要覆盖这些 tags,而应使用自己的名称命名。

一旦开始发送标记的数据(tagged data),您将在 Sentry Web UI 中看到它:Project 页面侧栏中的过滤器(filters),在事件内进行汇总以及在聚合事件(aggregated event)的 tags 页面上。

Attachments

Sentry 可以通过在事件旁边存储其他文件(例如日志文件)作为附件来增强崩溃报告。 附件使崩溃中的文件不仅可以上传到Sentry,而且可以持久保存以进行进一步调查。

Uploading Attachments

要添加 attachment,请创建一个事件处理器(event processor),该事件处理器以 multipart form data 请求的形式将文件上传到附件端点。这需要使用其 ID 将附件与事件相关联:

public attachmentUrlFromDsn(dsn: Dsn, eventId: string) {
  const { host, path, projectId, port, protocol, user } = dsn;
  return `${protocol}://${host}${port !== '' ? `:${port}` : ''}${
    path !== '' ? `/${path}` : ''
  }/api/${projectId}/events/${eventId}/attachments/?sentry_key=${user}&sentry_version=7&sentry_client=custom-javascript`;
}

Sentry.addGlobalEventProcessor((event: Event) => {
  try {
    const client = Sentry.getCurrentHub().getClient();
    const endpoint = attachmentUrlFromDsn(
      client.getDsn(),
      event.event_id
    );
    const formData = new FormData();
    formData.append(
      'my-attachment',
      new Blob([JSON.stringify({ logEntries: ["my log"] })], {
        type: 'application/json',
      }),
      'logs.json'
    );
    fetch(endpoint, {
      method: 'POST',
      body: formData,
    }).catch((ex) => {
      // we have to catch this otherwise it throws an infinite loop in Sentry
      console.error(ex);
    });
    return event;
  } catch (ex) {
    console.error(ex);
  }
});

Sentry 每个事件最多允许 100MB 的附件,包括崩溃报告文件(如果适用)。超过此大小的上传将被 HTTP 错误 413 Payload Too Large 拒绝,并且数据将立即被丢弃。要添加更大或更多的文件,请考虑使用辅助存储选项。

附件存留 30 天;如果超出了配额中包含的总存储空间,则不会存储附件。您可以随时删除附件或其包含的事件。删除附件不会影响您的配额(quota) - Sentry 存储附件后立即将其计入您的配额。

Access to Attachments

要限制对附件的访问,请导航到您组织的 General Settings,然后选择 Attachments Access 下拉菜单来设置适当的访问权限 - 您的组织的任何成员、组织帐单所有者、成员(member)、管理员(admin)、经理(manager)或所有者(owner)。

默认情况下,启用存储后,将授予所有成员访问权限。如果成员无权访问该项目,则无法下载附件。该按钮将在 Sentry 中显示为灰色。成员只能查看附件已存储。

Viewing Attachments

附件显示在所显示事件的 Issue Details 页面的底部。

或者,附件也会显示在 Issue Details 页面上的 Attachments 选项卡中,您可以在其中查看附件的类型以及相关事件。单击 Event ID,以打开该特定事件的 Issue Details 信息。

Breadcrumbs

Sentry 使用 breadcrumbs 创建事件发生之前的事件线索。这些事件与传统日志非常相似,但是可以记录更丰富的结构化数据。

此页面概述了手动 breadcrumb 录制(recording)和自定义(customization)。了解有关 Issue Details 页面上显示的信息的更多信息,以及如何过滤 breadcrumbs 以快速解决 Using Breadcrumbs 中的问题。

Manual Breadcrumbs

每当发生有趣的事情时,您都可以手动添加 breadcrumbs。例如,如果用户进行身份验证或发生其他状态更改,则可以手动记录一个面包屑。

Sentry.addBreadcrumb({
  category: "auth",
  message: "Authenticated user " + user.email,
  level: Sentry.Severity.Info,
});

可用的 breadcrumb keys 包括 type, category, message, level, timestamp(许多SDK会自动为您设置)和 data,在此处可以放置您希望包含面包屑的任何其他信息。使用这六个 key 以外的 key 不会导致错误,但是会导致在由 Sentry 处理事件时删除数据。

Automatic Breadcrumbs

SDK 及其相关的集成将自动记录许多类型的 breadcrumbs。例如,浏览器 JavaScript SDK 将自动记录所有 location 更改。

Customize Breadcrumbs

SDK 允许您通过 before_breadcrumb 挂钩自定义 breadcrumbs。此挂钩传递了已经组装好的 breadcrumb,并且在某些SDK 中传递了可选 hint。该函数可以修改 breadcrumb 或通过返回 null 决定完全放弃它:

Sentry.init({
  // ...

  beforeBreadcrumb(breadcrumb, hint) {
    return breadcrumb.category === "ui.click" ? null : breadcrumb;
  },
});

User Feedback

当用户遇到错误时,Sentry 可以收集其他反馈。当您通常可以呈现简单的错误页面(经典的500.html)时,这种类型的反馈非常有用。

要收集 feedback,请使用可嵌入的 JavaScript widget,该小部件将请求并收集用户的姓名,电子邮件地址以及发生的情况的描述。提供反馈后,Sentry 会将反馈与原始事件配对,从而使您对问题有更多见解。

下面的屏幕截图提供了 User Feedback 小部件的示例,尽管您的个性化可能因您的自定义而有所不同:

Collecting Feedback

要集成 widget,您需要运行 2.1 版或更高版本的 JavaScript SDK。该 widget 将使用您的公共 DSN 进行身份验证,然后传递在后端生成的 Event ID。

如果您希望使用 widget 的替代产品,或者没有 JavaScript 前端,则可以使用 User Feedback API。

确保您有可用的 JavaScript SDK:

<script
  src="https://browser.sentry-cdn.com/6.0.1/bundle.min.js"
  integrity="sha384-z2Rmh4rfoBkdxaENH00ggKo5Bx8b2SJs+MWQrjWx4DbET95Zr2mxV2Vet3CCj4iW"
  crossorigin="anonymous"
></script>

如果您使用的是 ReactAngular 之类的框架,则收集用户反馈的最佳位置是您的错误处理组件。(有关示例,请参阅特定于平台的文档。)如果您不使用框架,则可以在发送事件之前使用 beforeSend 收集反馈:

<script>
  Sentry.init({
    dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
    beforeSend(event, hint) {
      // Check if it is an exception, and if so, show the report dialog
      if (event.exception) {
        Sentry.showReportDialog({ eventId: event.event_id });
      }
      return event;
    },
  });
</script>

Customizing the Widget

您可以根据组织的需要自定义窗口小部件,尤其是为了本地化目的。所有选项都可以通过 showReportDialog 调用传递。

Sentry 的自动语言检测 override(例如 lang=de

ParamDefault
eventId手动设置事件的ID。
dsn手动设置要报告的dsn。
user手动设置 user data [具有下面列出的 key 的对象]。
user.email用户的电子邮件地址。
user.name用户名。
lang[automatic] – 覆盖 Sentry 的语言代码
title看来我们遇到了问题。
subtitle我们的团队已收到通知。
subtitle2如果您想提供帮助,请告诉我们下面发生的情况。 – 在小屏幕分辨率下不可见
labelName名称
labelEmailEmail
labelComments发生了什么?
labelClose关闭
labelSubmit提交
errorGeneric提交报告时发生未知错误。 请再试一次。
errorFormEntry有些字段无效。请更正错误,然后重试。
successMessage您的反馈已发送。 谢谢!
onLoadn/a

Scopes and Hubs

捕获事件并将其发送到 Sentry 后,SDK 会将事件数据与当前作用域(scope)中的额外信息合并。SDK 通常会在框架集成中为您自动管理 scopes,而您无需考虑它们。但是,您应该知道什么是 scope 以及如何利用它来发挥自己的优势。

What's a Scope, what's a Hub

您可以将 hub 视为我们的 SDK 用于将事件路由到 Sentry 的中心点。调用 init() 时,将创建一个 hub,并在其上创建一个 client 和一个 blank scope。然后,该 hub 与当前线程相关联,并将在内部保存一堆 scopes。

scope 将包含应与事件一起发送的有用信息。例如,contexts 或 breadcrumbs 存储在 scope 上。当推入作用域时,它将继承父作用域的所有数据,并且当其弹出时,所有修改都将还原。

默认的 SDK 集成将智能地推送和弹出作用域。例如,Web 框架集成将在您的路由(routes)或控制器(controllers)周围创建和销毁作用域。

How do the Scope and Hub Work

当您开始使用 SDK 时,将自动为您创建一个 scope 和 hub。hub 不太可能直接与之交互,除非您正在编写集成或希望创建或销毁作用域。另一方面,作用域更多地面向用户。您可以随时调用 configure-scope 修改存储在 scope 上的数据。例如,这用于 modify the context。

当您在内部调用诸如 capture_event 之类的全局函数时,Sentry 会发现当前的 hub 并要求其捕获事件。然后,hub 将在内部将事件与最高 scope 的数据合并。

Configuring the Scope

使用范围时,最有用的操作是 configure-scope 函数。它可用于重新配置当前 scope。例如,这可用于添加自定义标签或向 sentry 告知当前已通过身份验证的用户。

Sentry.configureScope(function(scope) {
  scope.setTag("my-tag", "my value");
  scope.setUser({
    id: 42,
    email: "john.doe@example.com",
  });
});

这也可以在注销时取消用户设置时应用:

Sentry.configureScope(scope => scope.setUser(null));

Local Scopes

我们还支持一键式推送和配置 scope。通常将其称为 with-scopepush-scope,如果您只想发送一个特定事件的数据,这也非常有用。在下面的示例中,我们使用该函数将 leveltag 附加到仅一个特定错误:

Sentry.withScope(function(scope) {
  scope.setTag("my-tag", "my value");
  scope.setLevel("warning");
  // will be tagged with my-tag="my value"
  Sentry.captureException(new Error("my error"));
});

// will not be tagged with my-tag
Sentry.captureException(new Error("my other error"));

尽管此示例看起来与 configure-scope 相似,但有很大的不同,从某种意义上说 configure-scope 实际上会更改当前的 active scope,所有对 configure-scope 的后续调用都将保留所做的更改。

另一方面,使用 with-scope 会创建当前作用域的副本,并保持隔离状态,直到函数调用完成。因此,您可以在此处不想设置其他位置的上下文信息,也可以通过在作用域上调用 clear 来根本不附加任何上下文信息,而“全局”范围保持不变。

中文文档陆续同步到:

我是为少。
微信:uuhells123。
公众号:黑客下午茶。
谢谢点赞支持👍👍👍!