介绍

前端应用 [稳定性] 没有保障 —— 测试永远无法做到100%覆盖, 用户也不会总是按照我们所预期的进行操作,因此我们需要在系统异常时主动对其进行收集上报,以制定解决方案。当生产环境中产生了一个 bug 时,如何做到迅速报警,找到问题原因,修复后又如何在线上验证?此时我们需要一个高效的错误监控系统。

搭建

环境

  • Docker 19.03.6+

  • Compose 1.24.1+

        # docker-compose# 1.安装sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose# 2.对二进制文件执行权限sudo chmod +x /usr/local/bin/docker-compose# 如果这一步遇到问题,可以创建/usr/bin路径建立链接sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose# 3.检查版本docker-compose --version复制代码
  • 最小内存 2GB RAM

准备

  • 仓库下载

  • SMTP邮件服务

    • 此处以QQ邮箱为例 ( 设置 - 账户 ) , 开启SMTP 服务, 开启之后需要保存好密钥

      前端监控Sentry 实践_Sentry

      点击 “ 什么是 IMAP,它又是如何设置?” 查看详细设置说明

安装

    ./install.sh复制代码

创建用户

根据提示创建管理员账户

启动服务

    # 构建docker-compose build# 启动服务docker-compose up -d    
复制代码

初始化设置

  • 初始化信息填写

    前端监控Sentry 实践_Sentry_02

  • 配置文件(初始化未填写或后期修改)

    前端监控Sentry 实践_Sentry_03

入口文件

import Vue from 'vue'import * as Sentry from "@sentry/vue";import pkg from '../package.json'Vue.config.devtools = trueVue.config.productionTip = falseconsole.log(`release: `, `${pkg.name}@${pkg.version}`);

Vue.prototype.$sentry = Sentry

Sentry.init({
  Vue,  dsn: process.env.VUE_APP_SENTRY_DSN,  release: `${pkg.name}@${pkg.version}`,  environment: process.env.NODE_ENV,  // is optional and is true if it is not provided. If you set it to false, Sentry will suppress sending all Vue components' props for logging.
  attachProps: true,  //is optional and is false if it is not provided. If you set it to true, Sentry will call Vue's original logError function as well.
  logErrors: false,  // 打开或关闭调试模式。如果启用了调试,则在发送事件出错时,SDK将尝试打印出有用的调试信息。默认值始终为false。通常不建议在生产debug中将其打开,尽管打开模式不会引起任何安全隐患。
  debug: process.env.NODE_ENV === 'development',  // autoSessionTracking: true,
  // integrations: [
  //   new Integrations.BrowserTracing(),
  //   // new Integrations.Vue({Vue, attachProps: true, logErrors: false}),
  // ],
  // tracingOptions: {
  //   trackComponents: true,
  // },
  // // We recommend adjusting this value in production, or using tracesSampler
  // // for finer control
  // tracesSampleRate: 1.0,});复制代码

SourceMap

.env 文件

VUE_APP_SENTRY_HOST=http://192.168.50.12:9000/
VUE_APP_SENTRY_ORG=example_org

VUE_APP_SENTRY_AUTH_TOKEN=c00606xxxxxxxx97bea62c2f
VUE_APP_SENTRY_DSN=http://1389e5a2c9xxxxxx3a1311a@192.168.50.12:9000/3复制代码

vue.config.js

if(process.env.NODE_ENV === 'production'){
  plugins.push(new SentryWebpackPlugin({      // sentry-cli configuration  authToken: process.env.VUE_APP_SENTRY_AUTH_TOKEN,      url:process.env.VUE_APP_SENTRY_HOST,      org: process.env.VUE_APP_SENTRY_ORG,      project: require('./package.json').name,      release: require('./package.json').version,      // webpack specific configuration  include: "./dist",      ignore: ["node_modules", "vue.config.js"],
    })
  );
}复制代码

常见问题

  • dsn 为空前端监控Sentry 实践_Sentry_04

  • 客户端用户数据携带

    docs.sentry.io/platforms/j…

        Sentry.setUser({ email: "john.doe@example.com" });复制代码
  • 第三方SDK监控

        <!-- script 标签添加 crossorigin="anonymous" 属性 -->复制代码

    默认情况下(未指定crossOrigin), cors不会使用。 在非同源情况下, 设置 anonymous关键子将不会通过cookies , 客户端SSL证书或HTTP认证交换用户凭据。当需要获取用户凭据的manifest 时,即使是同源的情况下属性值必须设置为use-credentials。

    简单来说,如果你的页面和页面中引用的 JavaScript 文件不同源(协议、域名、端口不一致),那么这些脚本抛出的错误都属于跨域错误 —— crossorigin="anonymous" 属性的添加可保证跨域错误的完整信息的捕获,但是crossorigin 属性需要服务端和浏览器同时支持。 服务端支持比较简单, 指定CORS响应头" Access-Control-Allow-Origin: * "即可, 但是浏览器端的支持情况就不太乐观,主要在IE和Safari上:

    前端监控Sentry 实践_Sentry_05

    基于上述的问题,有两种方案可以解决:

    • 把页面中所有的跨域资源放在跟页面同样的域下

    • 通过 Patch 原生方法来尽可能的捕获到错误, 比如我们可以Patch 原生的setTimeout:

      const prevSetTimeout = window.setTimeout;window.setTimeout = function(callback, timeout) {const self = this;return prevSetTimeout(function() {try {
                  callback.call(this);
              } catch (e) {// 捕获到详细的错误,在这里处理日志上报等了逻辑// ...throw e;
              }
          }, timeout);
      } 
      // 但 Patch 原生方法有诸多的不确定性,建议视具体场景采用复制代码
  • 主动上报

    Js中可以传入一个Error实例给 captureException() 以实现事件形式的主动捕获 —— 这种方式可能会抛出一个无法记录和回溯的错误字符串。

    // captureExceptiontry {
           aFunctionThatMightFail();
        } catch (err) {
            Sentry.captureException(err);
        }复制代码

    另外一种常见的方式是捕获要发送给 Sentry 的纯文本信息——它们对某些团队是很有用的。

        // captureMessageSentry.captureMessage("Something went wrong");复制代码