Sentry 前端日志上报使用

一.基本介绍

Sentry 是一个开源的实时错误追踪系统,可以帮助开发者实时监控并修复异常问题。

前端项目中上线代码都会经过编译、压缩等,当生产环境中出现异常时需要快速定位到具体报错的位置,快速修复,所以在上报异常时也需要将产生问题的 SourceMap 相关文件上传。

在具体使用时可以把项目部署在 Sentry 官方提供的系统内,也可以根据公司自身情况自己搭建 Sentry 系统。

当 Sentry 系统收集到错误信息时通过邮件等方式可以第一时间通知到开发人员。

二.搭建方式

  • 通过 Docker 安装

  • 通过 Python 安装

    一般都是由运维人员去安装搭建,详细内容自行了解,所以具体内容略。

三.系统设置

打开浏览器,对Sentry系统进行设置. 对时区设置是因为收集上报的错误信息的创建时间不是东八区的时间,看着不得劲。

  • 语言设置:左上角点击头像下拉框 -> User settings -> 在Account Details面板中设置Language:Simplified Chinese(简体中文)
  • 时区设置:左上角点击头像下拉框 -> User settings -> 在Account Details面板中设置Timezone:(UTC+0800) Asia/Shanghai

四.使用方式

4.1 通过script标签引入
a. 文件引用

需要同时按序引入 bundle.tracing.min.js、captureconsole.min.js 两个文件

<script src="./bundle.tracing.min.js">script>
<script src="./captureconsole.min.js">script>
b. 基本配置
try {
  Sentry.init({
    dsn: 'http://[email protected]:9000/3', // 密钥 DSN (数据源名称)告诉 SDK 将事件发送到何处,运维提供
    integrations: [
      new Sentry.Integrations.CaptureConsole({
        levels: ['error'], // 设置日志记录级别
      }),
    ],
    release: '1.0.0', // 代码版本,通过版本号可以知道产生的bug是由哪个版本发布产生的
    environment: 'production',
  })
} catch (e) {
  console.log('Sentry无法加载', e)
}
c. 测试

可以在浏览器中打开控制台尝试,然后在 Sentry 系统中就可以看到上报的错误信息。

Sentry.captureException('error test')
d. 注意事项
  1. 因为网络问题,所以需要将引用的文件下载存放在项目中,通过 cdn 的方式去访问的话可能会访问不到.
  2. 使用 try catch 使页面异常可控 ,保证程序能够继续执行。
  3. captureconsole.js 内部改写了 console.error()方法,使用时可以通过 throw new Error(‘XXX’) 或者 console.error(‘XXX’)上报异常信息。
4.2 通过 npm 包引入

请先查看下面的踩坑记录再进行安装使用.

安装依赖
# Using yarn
yarn add @sentry/browser @sentry/tracing
# Using npm
npm install --save @sentry/browser @sentry/tracing
使用
import * as Sentry from '@sentry/browser'
import { CaptureConsole as CaptureConsoleIntegration } from '@sentry/integrations'
import { SentryDSN, SentryLevels } from '@constants/Sentry'
import moment from 'moment'

/**
 * 入口文件中 Sentry初始化
 */
initSentry = () => {
  try {
    Sentry.init({
      dsn: SentryDSN,
      integrations: [
        new CaptureConsoleIntegration({
          levels: SentryLevels,
        }),
      ],
      release: moment().format('YYYY-MM-DD HH:mm'),
      environment: 'production',
    })
  } catch (e) {
    console.log('Sentry无法加载', e)
  }
}
配置解释
const BasicOptions = {
dsn: '',
release: '',
environment: '',
integrations: [],
}
Sentry.init(BasicOptions)
  1. dsn 秘钥:通过 dsn 告诉 SDK 将收集到的异常发往何处,如果没有这个值,SDK 将从 Sentry 的环境变量中读取,如果还是没有值,就不进行异常信息,所以该字段为必填.
    dsn的取值:左上角点击头像下拉框 -> Organization settings -> 项目 -> 选择要接入的项目名 -> 左侧面板下拉找 Client Keys (DSN) -> 就看到DSN的值了。
  2. release:收集到的异常信息归属于哪个代码版本,便于快速定位问题及相应开发人员。
  3. environment:设置环境,默认情况下不设置,默认值为 production。
  4. integrations:集成配置,参照 Webpack 的 plugin 理解
  5. levels:设置要记录收集的日志级别,可选项: [‘debug’,‘info’,‘warning’ ,‘error’,‘fatal’]
  6. 建议进行release和environment的配置,可以在Sentry系统中信息筛选的时候可以多维度高精度的查找信息。
{
    ...
    environment: process.env.RUN_ENV,  
    release: `${process.env.RUN_ENV}@${moment().format('YYYY-MM-DD')}`,
}
sourceMap上传

通过上传 sourceMap,Sentry 支持通过源映射查看原始未转换编译压缩的代码,通过版本号快速定位异常代码。
Sentry 通过抓取堆栈跟踪中的 url 自动获取源代码。

  1. 通过 sentry-cli 命令行:手动执行命令上传,后来尝试也可以通过 package.json 中多命令合并,在执行打包时上传源文件,但是版本号就得每次手动设置不够灵活。
  2. 通过 webpack 插件:打包时自动上传 sourceMap(官方推荐)
@sentry/cli
  1. 安装
  • window

    npm install -g @sentry/cli // 全局安装时确保身份权限root
    
    sentry-cli -V
    
  • 其它

    curl -sL https://sentry.io/get-cli/ | bash
    
  1. 获取 authToken:访问令牌。点击 Sentry 页面左下角头像,选择 API > Auth Tokens,点击右上角”Create New Token”按钮,勾选 project:write 权限,确认即可生成 Token。

  2. 登录 Sentry

  3. 使用 Sentry 官方提供系统: sentry-cli login (默认情况下,sentry-cli 将连接到 sentry.io)

  4. 公司自己搭建 Sentry 系统:sentry-cli --url https://myserver.invalid/ login (如:https://sentry.fescotech.com/)

  5. 在执行命令时注意必要的空格 Sentry 前端日志上报使用_第1张图片

  6. 登录成功后会提示创建了一个.sentrylrc 文件,根据提示路径,找到并打开。 【文件会创建在 C 盘 user 目录下,需要复制粘贴至项目根目录下.】

  7. 配置.sentrylrc 文件的相关信息: 补充url、org 和 project 信息到.sentrylrc。

    [auth]
    token=YOUR API TOKEN
    
    [defaults]
    url=服务器
    org=组织
    project=项目
    
    • 服务器:自建系统或者 Saas 版的 url
    • 组织:点击左上角头像选择 OrganizationSetting,在右侧 General 面板的 Organization Slug 选项
    • 项目:点击左侧菜单 Projects,选择找的项目卡片,顶部 Title 就是项目名
    • 配置完之后可以通过命令行执行 sentry-cli info 查看相关信息Sentry 前端日志上报使用_第2张图片
  8. 创建 release:两种方式

    • 在.sentrylrc文件中已经进行配置的情况下可以直接使用 sentry-cli releases new <版本号> 如:
    sentry-cli releases new dev@2021-01-01
    
    • 或者sentry-cli releases -o 组织 -p 项目 new <版本号>
      组织为自己项目所属的org.
      项目为当前项目project.
      官方推荐的release格式为:
      By default the SDK will read from Application.productName and Application.version to create the release in the format $"{Application.productName}@{Application.version}".
      如:
       sentry-cli releases -o sentry -p ssweb new dev@2021-01-01
      
    • 删除:
    sentry-cli releases -o 组织 -p 项目 delete <版本号>
    
  9. 上传 sourceMap:
    sentry-cli releases files upload-sourcemaps --url-prefix <线上资源URI> <打包出来的js文件所在目录>

     sentry-cli releases files dev@2021-01-01 upload-sourcemaps --url-prefix '' './dist'
    

    在windows的cmd下执行不灵,提示’./dist’系统找不到执行路径。
    通过package.json中配置脚本执行可以成功上传。【windows系统问题】
    删除sourceMap:

     sentry-cli releases files 发布版本号 delete --all
    
  10. 上传完成之后就可以进行错误信息测试的收集:
    -Sentry 前端日志上报使用_第3张图片
    Sentry 前端日志上报使用_第4张图片
    Sentry 前端日志上报使用_第5张图片
    Sentry 前端日志上报使用_第6张图片

  11. 至此 sentry-cli 的方式上传 sourceMap 完成。

@sentry/webpack-plugin
  1. 安装
    (npm\yarn 一直下载失败,最终改用cnpm下载)
npm install --save-dev @sentry/webpack-plugin
yarn add --dev @sentry/webpack-plugin
  1. 配置 webpack.config.js || 其它
const SentryWebpackPlugin = require("@sentry/webpack-plugin");

module.exports = {
    ...
    devtool: 'source-map',
    plugins: [
      ...
      new SentryWebpackPlugin({
        authToken: process.env.SENTRY_TOKEN,
        org: "XXX",
        project: 'XXX',
        release: 'XXX',
        include: "./dist",
        ignore: ["node_modules", "webpack.config.js"],
        urlPrefix: ''  
      }),
    ],
};

或者下面的代码(区别在于,Sentry 的配置信息 configFile)

plugins: [
    ...
    new SentryWebpackPlugin({
      release: '0.0.2',
      include: './dist',
      ignore: ['node_modules', 'webpack.config.js'],
      // configFile: "sentry.properties", 这是用来替代第二步的.sentryclirc文件。
      // 如果根项目有一个sentry.properties文件
      configFile: 'sentry.properties',
      urlPrefix: ''
    }),
]

本人目前的使用方式如下,实测可用(前提是项目根目录下存在.sentryclirc文件)。

plugins: [
    ...
    new SentryWebpackPlugin({
        environment: process.env.RUN_ENV,
        release: `${process.env.RUN_ENV}@${moment().format('YYYY-MM-DD')}`,
        include: "./dist",
        ignore: ["node_modules", "webpack.config.js", 'bundle.tracing.min.js', 'captureconsole.min.js'],
        urlPrefix: `http://${process.env.RUN_ENV === 'PRO' ? '10.0.91.23' : '10.0.75.59'}/ssweb/`,
      }),
]

urlPrefix为必须配置项。
需要注意的是urlPrefix的配置。urlPrefix指的是:线上对应的url资源的相对路径,而网上提供的配置:赋值为'~'即可,~表示项目的根目录,如果对应的uri资源不在根目录,后面加上对应的文件路径即可。 urlPrefix的设置可以作为常量提取。

但是在实际测试时这样配置无效,即使release和sourceMap都生成和上传成功,报错信息依然无法映射到源代码。所以此处urlPrefix设置为项目的域名。然后在Sentry系统中对应的版本号下查看sourceMap文件显示的是全路径。如http://10.0.75.59/ssweb/index.3e29e915.css.map

注意事项
  1. 常量提取
  2. try catch
  3. 可以在 Sentry 中给不同的环境配置不同的 token,在代码中通过 Process.env.SENTRY_TOKEN 去根据环境设置相应的 token 值.
  4. environment:有了上面的不同环境下的 sourceMap, 也就会产生不同环境下的错误收集信息,通过在 Sentry 系统中配置多环境,然后代码中通过 process.env.NODE_ENV 去设置相应的环境信息,当数据收集上报后在 Sentry 系统中就可以看到不同环境下的异常信息.
  5. 需要注意的是:即使生成了环境+版本,但是如果在该版本下没有收集到issues的话,在基于版本和环境的筛选条件下是看不到对应的版本信息的。

五.踩坑记录

  1. sentryclirc 文件配置的时候如果 org 配置不对会报 project not found 的错误
  2. roadhog 打包不生成.map 文件,无法映射。解决方式
  3. sentry-cli 上传成功 sourceMap 之后,浏览器中的报错收集上来无法存入对应的版本 release 中,测试过程中 ftp 没有同步上传最新的打包文件所以一直无法关联
  4. 创建 release 的时候需要注意不能使用非法字符,否则删不掉,目前测试通过的格式为DEV@2021-07-19, 逗号、分号、空格都不可用
  5. 删除版本 release 的时候需要先清空该版本关联的 issues 和 sourceMap,否则删不掉。即使清空了issues 和sourceMap之后有可能还需要再等两个小时才能删除,否则会报错提示该版本还有其它依赖。
  6. 在对sourceMap文件上传Sentry时,控制台会提示 caused by: sentry reported an error: unknown error (http status: 413)的错误信息,原因是要上传的map文件过大。解决方式 :需要修改nginx的配置文件信息:client_max_body_size的值需要往大了调,具体调多少看当前打包生成的map文件多大。调整后的值至少要比map文件大。
  7. 在实际项目使用中,通过webpack进行sourceMap上传进行版本跟map文件的关联。在页面入口文件中不需要再进行release的设置,如果对release的赋值方式用日期格式,会导致每天运行项目时都会产生一个新的版本,但是这个时候对应的sourceMap进行上传,会导致报错信息无法映射。如果对release的赋值方式用固定版本号 x.x.x 的话 可以使用。
  8. 当一个Sentry系统下有多个项目存在时,在设置版本号是如果是以 环境@日期 的格式设置,会出现一个版本号下会有多个项目,本应该是A项目上传上来的sourceMap 也会上传在该版本的下的别的项目中。所以在设置版本号时格式可以修改为 环境_项目名@日期 的格式。

六.相关扩展

React 中使用

基于ErrorBoundary组件,包裹在入口文件的结构外层。另外,Sentry 官网也提供了使用方式
1.定义组件

// ErrorBoundary.js
import React from 'react'

class ErrorBoundary extends React.Component {
    constructor(props) {
      super(props)
      this.state = { hasError: false }
    }
    
    componentDidCatch(error, info) {
      this.setState({ hasError: true })
      console.error(error, info)
    }
    
    render() {
      if (this.state.hasError) {
        return <h1>Something went wrong.</h1>
      }
      return this.props.children
    }
}
export default ErrorBoundary

2.使用:在页面的root节点之上的第一层节点外层包裹ErrorBoundary。

    <ErrorBoundary>
    	<Example />
    </ErrorBoundary>

3.本人使用的是自定义ErrorBoundary组件的方式,没有按官网提供的React使用方式。

Vue 中使用

1.模块安装

npm install --save  @sentry/vue @sentry/tracing

2.入口文件引入并配置

// 入口文件
import Vue from "vue";
import * as Sentry from "@sentry/vue";

import { Integrations } from "@sentry/tracing";
// 也可以入口文件中
// import { CaptureConsole as CaptureConsoleIntegration } from '@sentry/integrations';
// 然后组件中console.error('错误信息'),这样也可以收集上报
Sentry.init({
Vue: Vue,
dsn: "xxx",
integrations: [new Integrations.BrowserTracing()],
// 或者
// integrations: [
//	new CaptureConsoleIntegration({
//		levels: ['error'],
//  }),
// ],

// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
});

3.组件中异常收集用 throw New Error(‘xxx’) 获取console.error(‘xxx’)

错误信息定制

1.获取 bug 相关的上下文信息,如果只报错误信息,又没有相应数据的话,无法复现具体原因。封装 utils/collectionErrorInfo.js

import * as Sentry from '@sentry/browser';
/**
* 错误信息定制收集
* @param api:接口请求有误时上报相关信息。可以不传
* @param data:产生错误的上下文信息,如接口错误时的入参出参信息
* @param errorDesc:对该错误的文字描述
* 使用了 console.error 的方式上报
*/
const collectionErrorInfo = ({api = '',data = {},errDesc = '错误描述信息'}) => {
  Sentry.setTag('api', api)
  Sentry.setExtra('data', data)
  console.error(errDesc)
}
export default collectionErrorInfo
邮件配置

有错误信息产生时自动发送邮件

钉钉配置

有错误信息产生时钉钉内机器人自动通知

前端的异常捕获
  • trycatch:对可能产生异常的代码进行包裹进行异常处理,保证程序能够继续执行
  • window.onerror(): 可以进行全局异常监听
  • 使用 Promise 时需要在 catch()中做异常处理
监控原理
  • 传统的前端监控原理分为异常捕获和异常上报,一般使用 onerror 捕获前端错误

  • window.addEventListener('error', (msg, url, row, col, error) => {
      console.error(msg, url, row, col, error)
    })
    
  • 但是 onerror 事件无法捕获到网络异常的错误(图片资源加载失败、图片显示异常等),例如 img 标签下图片 url404 网络请求异常的时候,onerror 无法捕获到异常,此时需要监听 unhandledrejection

  • window.addEventListener('unhandledrejection', function (e) {
      e.preventDefault()
      console.error(e.reason)
    })
    

七.最后

总体来说,使用 Sentry 可以捕获各种类型的异常事件。在代码任意地方通过 console.error()或者 throw new Error(的方式)做任意信息的收集上报,而具体的上报信息格式看各自的需要设置。而 Sentry 也可以捕获上报任意代码未处理的异常信息。

在 Sentry 收集上报错误信息的时候,也会将上下文的接口信息、console.log()信息上报,通过 log 的上下文信息也可以对 bug 进行分析。

所以可以使用 Sentry 对一些接口偶发性异常做数据收集,拿到真实的数据去分析代码遗漏的场景。

Sentry 前端日志上报使用_第7张图片

你可能感兴趣的:(前端)