Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript集成Sentry #1

Open
BlackHole1 opened this issue Aug 24, 2018 · 2 comments
Open

JavaScript集成Sentry #1

BlackHole1 opened this issue Aug 24, 2018 · 2 comments

Comments

@BlackHole1
Copy link
Contributor

BlackHole1 commented Aug 24, 2018

Sentry-JavaScript

Sentry是一套用于捕获产品错误的开源项目,其下支持很多语言、框架。

这里就只阐述在前端JavaScript方向的处理操作

在我们公司之前的应用场景里,很多项目都是使用kibana来做信息统计。但是我们无法清楚的知道应用的运行状态是怎么样的。当某个客户在使用我们开发产品时,如果报错、崩溃。用户只能向客服寻求帮助,再交接给我们的开发人员进行复现、修复。其中因为不清楚具体的数据,开发人员是在复现时会非常的耗时。

Sentry的用途就是解决这一痛点问题,让开发人员快速准确的定位到问题的根源所在,以达到快速修复,让开发人员更注重于开发新的功能上面。减少时间资源上的浪费。

1. JavaScript

1.1. 接入

因为Sentry使用的是一种Hook错误函数的技术,来达到捕获错误的目的,所以我们基本可以无损耗的接入到现有的项目中去。

下面是ReactSentry进行结合的一些基本步骤。

React:

#SentryBoundary.js
import { Component } from "react";
import Raven from "raven-js";

export default class SentryBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error });
    // 发送错误信息
    Raven.captureException(error, { extra: errorInfo });
  }

  render() {
    if (this.state.error) {
      // 此处可以写成组件,当组件崩溃后,可以替换崩溃的组件
      console.log("React Error");
    }
    return this.props.children;
  }
}
#index.js
Raven.config("DSN", {
  release: release,
}).install();

ReactDOM.render(
  <div>
    <SentryBoundary>
      <App />
    </SentryBoundary>
  </div>,
  document.getElementById("root")
);

1.1.1. 上传source-map

如果上面的代码已经配置好后,那么现在的应用是可以捕获到错误的,但是存在了一个问题,我们目前的项目大多都使用webpack进行打包,而打包后的代码是混淆加密的代码,无法让我们准确的知道抛出错误的位置在哪里。所以我们需要上传source-map和混淆后的文件一起上传到Sentry服务器上。方便我们快速查找到问题所在的位置。

这个上传的配置及命令是比较繁琐的。也是项目结合Sentry的一个难点。

上传source-map目前有两种方式:

  • 使用Sentry提供的Webpack插件进行配置,但是其灵活性不高。
  • 使用sentry-cli的,其灵活性比较高,可以针对不同项目进行单独的配置。

其配置较为繁琐,这里就不在阐述。具体的React与Sentry结合的例子。可见我在github上的项目: react-sentry-demo。对每个配置都有详细的说明。其中的上传source-map,我使用的是第二种方法,并写了一个脚本,实现了: 打包、环境检测、认证检测、上传source-map、删除本地source-map的操作,完成自动化,可以把脚本直接迁移到现有的项目中去,改动也不会太大。

其核心上传命令如下:

sentry-cli releases files v1.8 upload-sourcemaps {js文件和js.map所在目录。如果没有找到,sentry会遍历其子目录} --url-prefix '~/{过滤规则}'`;

1.2. 浅入原理

在JavaScript中是有window.onerror这个方法的,而Sentry在前端的核心捕获原理,就是通过重写此方法,来对所有的错误进行捕获。其实现的代码大致如下:

let _winError = window.onerror;
window.onerror = function (message, url, lineNo, colNo, errorObj) {
    console.log(`
	错误信息: ${message}
	错误文件地址: ${url}
	错误行号: ${lineNo}
	错误列号: ${colNo}
	错误的详细信息 ${errorObj}`);
}

然后Sentry的工作就是获取非错误的数据,如: user-agent浏览器信息系统信息自定义信息等信息,然后交给Sentry的生命周期函数,最后在把数据发送到Sentry服务端,进行错误信息展示。

1.2.1. 兼容性

这里所说的兼容性,其实也就是window.onerror的兼容性

1.2.1.1. 运行环境兼容性

环境 message url lineNo colNo errorObj
Firefox
Chrom
Edge
IE 11
IE 10
IE 9
IE 8
Safari 10 and up
Safari 9
Opera 15+
Android Browser 4.4
Android Browser 4 - 4.3
微信webview(安卓)
微信webview(IOS)
WKWebview
UIWebview

1.2.1.2. 标签兼容性

标签 window.onerror是否能捕获
img 可以
script 需要再script标签添加 crossorigin属性,并在服务端允许跨域。如果不使用这个属性,错误信息只会显示Script error.
css 不能
iframe 不能

可以发现其浏览器都支持此方法。只是有些运行环境不支持colNoerrorObj,但是这块,Sentry已经帮你处理好了,所以不用担心。只是会在展示错误的时候,信息不太完整而已。

1.3. 所能捕获的信息

1.3.1. 错误信息

从上面的浅入原理可以看到,其核心捕获是window.onerror。那么只要它可以捕获到的错误,都会发送到Sentry上。

window.onerror能捕获到的错误,除了Promise,基本上能在控制台出现的错误,都会捕获到。也就是运行时的错误,包括语法错误。

关于捕获Promise错误的方案,可以使用:

window.addEventListener('unhandledrejection', event => {})

来进行捕获,但是此事件的兼容性不太好,目前只有webkit内核支持这个事件。

如下代码,是此方法所能捕获到的:

const p = new Promise((reslove, reject) => reject('Error'))
p.then(data => {
  console.log(data)
})
// Promise触发了reject回调函数,但是却没有相应到catch来应对。从而导致报错。

1.3.2. 面包屑信息

  • Ajax请求
  • URL地址的变化
  • UI点击和按下的DOM事件
  • 控制台的console信息
  • 之前的错误
  • 自定义的面包屑信息

1.4. 展示信息

image

2. Electron集成

这里的集成,也不是说捕获Electron应用的错误,而是崩溃。因为Electron只是一个容器,里面的内容还是JavaScript应用。

2.1 接入

刚刚也说到这里的集成也只是去捕获Electron崩溃的信息。而当Electron崩溃时,会触发Electron的函数:crashReporter.start,那么我们在这个函数里去配置一下自己的sentry信息:

import { crashReporter } from 'electron'

crashReporter.start({
  productName: 'aoc-desktop',
  companyName: 'alo7',
  submitURL:
    'https://sentry.com/api/34615/minidump/?sentry_key=3e05fe101f1f85008e853ff56908b7eb',  // sentry提供的minidump接口
  extra: {
    // 额外信息
  }
})

配置好后,可以使用process.crash()来模拟崩溃,以便查看Sentry是否能收到崩溃信息。

2.1.1 上传Symbol(符号表)

在上面的应用说的是上传source-map,但是这里上传的是Symbol。可以把Symbol理解为另一种source-map

Symbol的格式(后缀)有很多,Mac下是dSYM,windows是pdb。而在Sentry里,暂时是不支持上传pdb的。需要使用dump_syms.exe来把pdb格式转化成sym格式。再上传到Sentry里。这样就可以在Sentry崩溃的时候,看到起崩溃的上下文了。如下图:

这样就可以准确的定位到是哪里出现了问题。

3. 浅入上传检索的原理

当Sentry服务端收到source-map时,是通过你上传时的url-prefix信息,与source-map文件以及运行时的js文件,产生对应。流程图如下:

@liubiantao
Copy link

@BlackHole1 你图挂了

@BlackHole1
Copy link
Contributor Author

@liubiantao 已经修复啦

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants