Sentry接入实战

717 阅读12分钟

Sentry接入使用

上家公司的技术栈很老,所以选择的项目版本也一般在两三年前发布的。

选择的版本

  "@sentry/cli": "^1.74.4",
​
  "@sentry/integrations": "^6.14.0",
​
  "@sentry/tracing": "^6.14.0",
​
  "@sentry/vue": "^6.14.0",
​
  "@sentry/webpack-plugin": "^1.20.0",

适配14.16.1

请每次运行时检查服务器上sentry的运行状态,经常未使用极有可能服务挂掉,但是网站完好。

Vue2接入

​
​
import * as Sentry from '@sentry/browser'
import { Integrations } from '@sentry/tracing'Sentry.init({
  Vue,
  logErrors: true, 
  release: 'v1.0.2',
  dsn: '',
  integrations: [new Integrations.BrowserTracing({})],
  tracesSampleRate: 1.0,
  release: 'v1.0.3',
  beforeSend(event, hint) {
    const isNonErrorException =
      event.exception.values[0].value.startsWith('Non-Error exception captured') ||
      hint.originalException['message'].startsWith('Non-Error exception captured')
​
    if (isNonErrorException) {
      // We want to ignore those kind of errors
      return null
    }
    return event
  },
})
// //把vue warn报的错发送到sentry,但是如果不想在开发环境中上传错误,可以在这里加一个判断(或者注释掉)
Vue.config.errorHandler = function(err, vm, info) {
  console.log(err, vm, info)
  Sentry.withScope((scope) => {
    scope.setExtra('info', info)
    scope.setExtra('component', vm)
    Sentry.captureException(err)
  })
}
​

Vue3接入

import { createApp } from "vue";
import { createRouter } from "vue-router";
import * as Sentry from "@sentry/vue";
import { Integrations } from "@sentry/tracing";
​
const app = createApp({
  // ...
});
const router = createRouter({
  // ...
});
​
Sentry.init({
  app,
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    new Integrations.BrowserTracing({
      routingInstrumentation: Sentry.vueRouterInstrumentation(router),
      tracingOrigins: ["localhost", "my-site-url.com", /^//],
    }),
  ],
  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for performance monitoring.
  // We recommend adjusting this value in production
  tracesSampleRate: 1.0,
});
​
app.use(router);
app.mount("#app");

常见选项

SDK 的常用选项列表。这些在所有 SDK 中的工作方式或多或少都相同,但为了更好地支持平台,将存在一些细微差别。 可以从环境变量(SENTRY_DSNSENTRY_ENVIRONMENTSENTRY_RELEASE)中读取的选项会自动读取。

dsn

DSN 告诉 SDK 将事件发送到哪里。如果没有提供这个值,SDK 将尝试从 SENTRY_DSN 环境变量中读取它。如果这个变量也不存在,SDK 就不会发送任何事件。

在没有进程环境(如浏览器)的运行时中,fallback 不会应用。

更多:docs.sentry.io/product/sen…

debug

打开或关闭调试模式。如果启用了调试,如果发送事件时出现问题,SDK 将尝试打印出有用的调试信息。默认值总是 false。一般不建议在生产环境中打开它,尽管打开 debug 模式不会引起任何安全问题。

release

设置 release。某些 SDK 会尝试自动配置 release,但是最好手动设置 release,以确保该 release 与您的 deploy integrationssource map uploads 同步。Release 名称是字符串,但是 Sentry 会检测到某些格式,并且它们的呈现方式可能有所不同。

更多:docs.sentry.io/product/rel…

默认情况下,SDK 会尝试从环境变量 SENTRY_RELEASE 中读取该值(在浏览器 SDK 中,将从 window.SENTRY_RELEASE 中读取该值,如果可用)。

environment

设置环境。此字符串为自由形式,默认情况下不设置。一个 release 可以与多个环境相关联,以便在 UI 中将它们分开(可以考虑stagingprod 或类似的方式)。

默认情况下,SDK 将尝试从 SENTRY_ENVIRONMENT 环境变量中读取该值(浏览器 SDK 除外)。

tunnel

设置将用于传输捕获事件的 URL,而不是使用 DSN。这可用于解决广告拦截器(ad-blockers)或对发送到 Sentry 的事件进行更精细的控制。此选项需要实现自定义服务器端点。

更多:docs.sentry.io/platforms/j…

sampleRate

配置错误事件的采样率,范围为 0.01.0。默认值为 1.0,表示发送了 100% 的错误事件。如果设置为 0.1,则仅发送 10% 的错误事件。事件是随机选择的。

maxBreadcrumbs

这个变量控制应该捕获的面包屑总数。默认值为 100

attachStacktrace

当启用时,堆栈跟踪将自动附加到所有记录的消息。堆栈跟踪总是附加到异常;然而,当设置此选项时,堆栈跟踪也会与消息一起发送。例如,该选项意味着堆栈跟踪显示在所有日志消息的旁边。

该选项默认为 off

Sentry 中的分组对于有和没有堆栈跟踪的事件是不同的。因此,当您为某些事件启用或禁用此 flag 时,您将获得新组。

denyUrls

与不应该发送到 Sentry 的错误 URL 相匹配的字符串或正则表达式模式列表。默认情况下,将发送所有错误。这是一个 “contains(包含)” 匹配整个文件 URL。因此,如果你添加 foo.com,它也会匹配 https://bar.com/myfile/foo.com。默认情况下,将发送所有错误。

allowUrls

匹配错误 URL 的字符串列表或正则表达式模式的遗留别名,这些错误 URL 应该专门发送给 Sentry。默认情况下,将发送所有错误。这是一个 “contains(包含)” 匹配整个文件 URL。因此,如果您将 foo.com 添加到它,它也将匹配 https://bar.com/myfile/foo.com。默认情况下,所有错误将被发送。

autoSessionTracking

设置为 true 时,SDK 将向 Sentry 发送 session 事件。这在所有浏览器 SDK 中都受支持,每个页面加载和页面导航都向 Sentry 发出一个 session。在移动 SDK 中,当应用进入后台超过 30 秒时,会话结束。

initialScope

要设置为初始作用域的数据。初始作用域可以定义为对象或回调函数

注意

Vue 错误处理

请注意,如果你启用这个集成,默认情况下 Vue 不会在内部调用它的 'logError'。这意味着 Vue 渲染器中发生的错误不会显示在开发者控制台中。 如果要保留此功能,请确保传递“logErrors: true”选项。

过滤错误事件

通过使用 beforeSend 回调方法和配置、启用或禁用集成来配置您的 SDK 以过滤错误事件。

使用 beforeSend

所有 Sentry SDK 都支持 beforeSend 回调方法。beforeSend 在事件发送到服务器之前立即调用,因此它是您可以编辑其数据的最后位置。它将事件对象作为参数接收,因此您可以使用该参数根据自定义逻辑和事件上可用的数据修改事件的数据或完全删除它(通过返回 null)。

Sentry.init({
  // ...
​
  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});

Event Hints

before-send 回调传递 event 和第二个参数 hint,该参数包含一个或多个 hints

通常,hint 保存原始异常,以便可以提取附加数据或影响分组。 在本例中,如果捕获到某种类型的异常,指纹将被强制为一个公共值:

Sentry.init({
  // ...
​
  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});

有关哪些 hints 可用的信息,请参阅:

SDK 创建用于传输(transmission)的事件或面包屑时,该传输通常是从某种源对象创建的。例如,错误事件通常是从日志记录或异常实例中创建的。为了更好地定制,SDK 将这些对象发送到某些回调(beforeSendbeforeBreadcrumb 或 SDK 中的事件处理器系统)。

使用 Hints

Hints 可在两个地方获得:

  1. beforeSend / beforeBreadcrumb
  2. eventProcessors

事件和面包屑 hints 是包含用于组合事件或面包屑的各种信息的对象。 通常 hints 保存原始异常,以便可以提取附加数据或影响分组。

对于事件,例如 event_idoriginalExceptionsyntheticException(在内部用于生成更清晰的堆栈跟踪)以及您附加的任何其他任意数据。

对于面包屑,hints 的使用取决于实现。对于 XHR 请求,hint 包含 xhr 对象本身;对于用户交互,提示包含 DOM 元素和事件名称等。

在本例中,如果捕获到某种类型的异常,指纹将被强制为一个公共值:

Sentry.init({
  // ...
​
  beforeSend(event, hint) {
    const error = hint.originalException;
    if (
      error &&
      error.message &&
      error.message.match(/database unavailable/i)
    ) {
      event.fingerprint = ["database-unavailable"];
    }
    return event;
  },
});

Hints for Events

originalException

导致 Sentry SDK 创建事件的原始异常。这对于更改 Sentry SDK 分组事件的方式或提取附加信息很有用。

syntheticException

当引发字符串(string)或非错误(non-error)对象时,Sentry 会创建一个合成异常(synthetic exception),以便您可以获得基本的堆栈跟踪。 此异常存储在此处以供进一步提取数据。

Hints for Breadcrumbs

event

对于从浏览器事件创建的面包屑,Sentry SDK 通常将事件作为 hint 提供给面包屑。例如,这可用于将目标 DOM 元素中的数据提取到面包屑中。

level / input

对于从控制台日志(console.log)拦截创建的面包屑。 这保存了原始 console log levellog function 的原始输入数据。

response / input

对于从 HTTP 请求创建的面包屑。它保存响应对象(来自 fetch API)和 fetch 函数的输入参数。

request / response / event

对于从 HTTP 请求创建的面包屑。这包含请求和响应对象(来自 node HTTP API)以及 node eventresponseerror)。

xhr

对于通过遗留 XMLHttpRequest API 完成的 HTTP 请求创建的面包屑。这保存了原始的 xhr 对象。

采样 Error 事件

要将具有代表性的错误样本发送到 Sentry,请将 SDK 配置中的 sampleRate 选项设置为 0(发送的错误的 0%)和 1(发送的错误的 100%)之间的数字。 这是一个静态比率,它同样适用于所有错误。例如,要对 25% 的错误进行抽样:

Sentry.init({ sampleRate: 0.25 });

更改错误采样率需要重新部署。 此外,设置 SDK 采样率会限制对事件源的可见性。 为您的项目设置速率限制(仅在 volume 高时丢弃事件)可能更适合您的需求。

设置统一采样率

为此,请将 Sentry.init() 中的 tracesSampleRate 选项设置为 01 之间的数字。设置此选项后,创建的每个 transaction 都有该百分比的机会被发送到 Sentry。(因此,例如,如果您将 tracesSampleRate 设置为 0.2,大约 20%transaction 将被记录和发送。)看起来像这样:

Sentry.init({  *// ...*   tracesSampleRate: 0.2, });

错误类型

Error,最基本的错误类型,其他的错误类型都继承自该类型。通过 Error,我们可以自定义 Error 类型。

RangeError: 范围错误。当出现堆栈溢出(递归没有终止条件)、数值超出范围(new Array 传入负数或者一个特别大的整数)情况时会抛出这个异常。

ReferenceError,引用错误。当一个不存在的对象被引用时发生的异常。

SyntaxError,语法错误。如变量以数字开头;花括号没有闭合等。

TypeError,类型错误。如把 number 当 str 使用。

URIError,向全局 URI 处理函数传递一个不合法的 URI 时,就会抛出这个异常。如使用 decodeURI('%')decodeURIComponent('%')

EvalError, 一个关于 eval 的异常,不会被 javascript 抛出。

在最基本的情况下,直接传递值:

function makeRequest(method, path, options) {
  return fetch(method, path, options).catch(function(err) {
    Sentry.withScope(function(scope) {
      // group errors together based on their request and response
      scope.setFingerprint([method, path, String(err.statusCode)]);
      Sentry.captureException(err);
    });
  });
}

您可以使用变量替换将动态值填充到通常在服务器上计算的指纹中。 例如,可以添加值 {{ default }} 以将整个正常生成的分组哈希添加到指纹中。 这些值与服务器端指纹识别相同。有关更多信息,请参阅:

Variables: docs.sentry.io/product/dat…

以更大的粒度对错误进行分组

您的应用程序查询远程过程调用模型 (RPC) 接口或外部应用程序编程接口 (API) 服务,因此堆栈跟踪通常是相同的(即使传出请求非常不同)。

以下示例将进一步拆分 Sentry 将创建的默认组(由 {{ default }} 表示),并考虑到错误对象的一些属性:

class MyRPCError extends Error {
  constructor(message, functionName, errorCode) {
    super(message);

    // The name of the RPC function that was called (e.g. "getAllBlogArticles")
    this.functionName = functionName;

    // For example a HTTP status code returned by the server.
    this.errorCode = errorCode;
  }
}

Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;

    if (exception instanceof MyRPCError) {
      event.fingerprint = [
        '{{ default }}',
        String(exception.functionName),
        String(exception.errorCode)
      ];
    }

    return event;
  }
});

更进一步地分组错误

通用错误(例如数据库连接错误)具有许多不同的堆栈跟踪,并且永远不会组合在一起。

以下示例将通过从数组中省略 {{ default }} 来完全覆盖 Sentry 的分组:

class DatabaseConnectionError extends Error {}

Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;

    if (exception instanceof DatabaseConnectionError) {
      event.fingerprint = ['database-connection-error'];
    }

    return event;
  }
});

具有“非错误异常Non-Error Exception”的事件

如果您看到错误消息 “Non-Error exception (or promise rejection) captured with keys: x, y, z.”,这会发生在您 a) 使用 plain object 调用 Sentry.captureException() 时,b) 抛出一个 plain object,或者 c) 拒绝一个带有 plain objectpromise

您可以在 “Additional Data” 部分的 __serialized__ 条目中查看有问题的非错误对象的内容。

为了更好地了解这些错误事件,我们建议根据 __serialized__ 数据的内容找到 plain object 被传递或抛出到 Sentry 的位置,然后将 plain object 转换为 Error 对象。

Source Maps

虽然知道错误内容,可是我们不知道具体在哪个组件的哪一行。这是因为用 webpack 打包过程中会将js文件进行压缩混淆等,因此要准确定位到错误,需要我们将 sourcemap 也上传一份供 sentry 解析,这里提供了两种方式,可以在 官网 中查看资料

生成 Source Maps

使用方法:安装 @sentry/webpack-plugin

const SentryWebpackPlugin = require("@sentry/webpack-plugin");

module.exports = {
  // other webpack configuration
  devtool: 'source-map',
  plugins: [
    new SentryWebpackPlugin({
      // sentry-cli configuration - can also be done directly through sentry-cli
      // see https://docs.sentry.io/product/cli/configuration/ for details
      authToken: process.env.SENTRY_AUTH_TOKEN,
      org: "example-org",
      project: "example-project",
      release: process.env.SENTRY_RELEASE,

      // other SentryWebpackPlugin configuration
      include: ".",
      ignore: ["node_modules", "webpack.config.js"],
    }),
  ],
};
  1. [Account] > API keys 创建一个新的身份验证令牌
  2. 确认您在“Scopes”下选择了 project:write
  3. 使用 npm 安装 @sentry/webpack-plugin
  4. 使用必要的配置创建 .sentryclirc 文件,如本页所述
  5. 更新你的 webpack.config.js

.sentryclirc

[auth]  
token=aef6561e0ed54f309b4125ff45a0ac0e37da629f28254c36992f61ec8a26d08b
​
[defaults]
url = http://192.168.0.237:9000/
project=vue23
org=sentry

弊端

parallel: require('os').cpus().length > 1, // 构建时开启多进程处理babel编译

打包时速度变慢,并且强制 productionSourceMap: true,

Sentry自身报错多

可能是版本或者服务器内部服务挂了,目前把Vue的捕捉错误发送给了sentry

特别注意!! ,这个 --url-prefix 是你线上访问到js文件的路径,~ 就是你网站的根目录,比如我网站的静态文件是这样 http://192.168.144.163:8080/static/js/xxxx.js,那么按照上面例子填就是正确的,因为我网站根目录就是 http://192.168.144.163:8080,上传成功后可以在 Releases -> Artifacts 中看到刚才上传的文件

搭建完成后,一旦有错误时我们就可以实时收集到,并可以看到错误的具体详情,分析然后排查问题,对于一些偶现的BUG很有作用,当然,sentry 能做到的只是查找你代码上发生的问题,对于业务上的错误还是要通过其他一些方法记录啦