文档章节

前端一站式异常监控捕获方案

ouven
 ouven
发布于 2017/05/03 15:10
字数 1212
阅读 1988
收藏 118

一、前端异常监控的重要性

  软件异常监控常常直接关联到软件本身的质量,完备的异常监控体系常常能够快速定位到软件运行中发生的问题,并能帮助我们快速定位异常的源头,提升软件质量。

  在服务器开发中,我们常常使用日志来记录请求的错误和服务器异常问题,但是在客户端,前端应用直接部署运行在用户的浏览器中,如果发生错误,应该怎样去捕获并传送给服务器呢?前端错误日志传送给服务器很简单,在异常发生时直接发请求就可以了,下面我们主要讨论下错误的捕获方案。

二、现有的异常监控方案

  • window.onerror全局异常捕获

  目前前端捕获页面异常的方式主要有两种,window.onerror捕获整个页面中运行的错误,它的局限是对于跨域的JavaScript脚本需要添加跨域支持,也就是需要涉及服务器的修改成本,否则无法获取到运行时具体的堆栈错误信息,而是"script error"的信息,不利于我们定位问题。

window.onerror = function(msg, file, row, column, errorObj) {
    console.log(msg); // script error.
    console.log(file); // 
    console.log(row); // 0
    console.log(column); // 0
    console.log(errorObj); // {}
    setTimeout(function() {
        // 发送请求上报日志信息
        errorReport(e.name, e.message + e.stack);
    }, 5000);
}
<script src="//domain.com/path/main.js" crossorigin></script>
  • try-catch运行时解决方案

  现有的另一中方案则是try-catch,对于某个方法函数,我们可以这样定义来捕获函数里面运行时的异常,但是try-catch只能捕获当前单个作用域下的异常。另外,使用try-catch会带来一定的性能损耗,根据循环测试,平均大概会损失6%~10%的性能,但是为了提升应用的质量和稳定性,这些是可以接受的。

function wrapFunction(fn) {
    return function() {
        try {
            return fn.apply(this, arguments);
        } catch (e) {
            console.log(e);
            _errorProcess(e);
            return;
        }
    };
}

// 之后fn函数里面的代码运行出错时则是可以被捕获到的了
fn = wrapFunction(fn);

// 或者异步函数里面的回调函数中的错误也可以被捕获到
var _setTimeout = setTimeout;
setTimeout = function(fn, time){
    return _setTimeout(wrapFunction(fn), time);
}

// 模块定义函数也可以做重写定义
var _require = require;
require = function(id, deps, factory) {
    if (typeof(factory) !== 'function' || !factory) {
        return _require(id, deps);
    } else {
        return _require(id, deps, wrapFunction(factory));
    }
};

  那么我们可以对常用的模块入口函数进行重定义,包括define,require等,这样模块中的主要作用域中的异常都可以通过try-catch来捕获了。在之前的处理方法中,这种方法是非常有效的,直接可以拿到大多数错误栈中的异常和堆栈信息。

三、改进的一站式解决方案

  React开发时代,这种方式就不能直接使用了,我们知道React的组件都是class,其实也就是构造函数,这里普及下class和构造函数其实是非常类似的,class A除了constructor为class A,其它信息和function A类似,typeof获取的类型也相同。但是我们是没办法把构造函数A直接装入try-catch中运行的,因为需要通过关键字new进行实例化,并创建新的作用域。

  此时我们要处理的问题其实是捕获React中属性方法中的错误,应该还记得,JavaScript中函数有个特殊的属性prototype,当函数作为构造函数是,prototype中的属性就成了实例化后的属性方法,而且这一属性对class同样生效。那么我们可以对React中class的prototype这个特殊属性的内容进行处理,对Component中的方法函数进行封装。

function defineReact(Component) {

    var proto = Component.prototype;

    for (var key in proto) {
        if (typeof(proto[key]) === 'function') {
            proto[key] = _wrapFunction(proto[key]);
        }
    }

    return Component;
}

  这样通过实例化产生的React组件中的内部方法中的错误就可以被捕获到了。

class component extends React.Component {
    componentDidMount(){
        var a = {};
        console.log(a.b.c);
    }
    render() {
        return <div>hello world</div>;
    }
}
export default defineReact(component);

  这里添加defineReact的操作就可以放到构建打包工具中去处理了,这样就避免了我们对代码层直接进行修改。

React直接报错不利于定位问题

封装后直接获取堆栈错误

四、小结

  小结一下,其实和原有的方式差别不大,仍然通过try-catch的方式,覆盖到React组件prototype属性中进行异常捕获,极大增加了错误捕获范围,不仅能帮助我们快速定位开发中的问题,也能捕获React线上应用的运行时错误。

完整例子:https://github.com/ouvens/tryjs

原文链接:http://jixianqianduan.com/frontend-weboptimize/2017/05/04/front-end-react-error-capture.html

© 著作权归作者所有

共有 人打赏支持
ouven

ouven

粉丝 108
博文 30
码字总数 77829
作品 0
深圳
高级程序员
私信 提问
前端异常监控、上报及js压缩代码定位

最近在研究前端异常监控的问题,对查询的资料做了整理汇总,总体如下 一、前端异常监控方式 1. window.onerror 异常处理 window.onerror 无论是异步还是非异步错误,onerror 都能捕获到运行时...

Keely袁庆玲
08/05
0
0
4000+系统,10w+服务的立体式监控是如何炼成的?

在高效地支撑苏宁互联网相关业务的过程中,各系统间的交互也变得如图 1 一样错综复杂,下图中的点代表各个应用系统,连线代表系统间的交互。 图 1:系统交互图 以上错综复杂的特性主要由以下...

51CTO技术栈
09/05
0
0
Spring事务异常回滚,捕获异常不抛出就不会回滚

最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志。但是这边情况来了,当这个方法异常时候 日志是打...

binhu
2015/11/23
218
0
Spring事务异常回滚,捕获异常不抛出就不会回滚

最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志。但是这边情况来了,当这个方法异常时候 日志是打...

巴顿
2016/01/05
47
0
06-《深度拆解JVM》之JVM是如何处理异常的?

一、问题引入 今天我们来讨论下 Java 虚拟机的异常处理。众所周知,异常处理的两大组成要素是抛出异常和捕获异常。这两大要素共同实现程序控制流的非正常转移。 抛出异常可分为显式和隐式两种...

飞鱼说编程
09/28
0
2

没有更多内容

加载失败,请刷新页面

加载更多

Java 主要特性

Java 有下面的一些主要特性。 面向对象 在 Java 中,所有的都是对象。正式因为 Java 基于对象模型,所以 Java 更加容易进行扩展。 Java语言提供类、接口和继承等面向对象的特性,为了简单起见...

honeymose
44分钟前
1
0
【NLP】【五】gensim之Word2Vec

【一】整体流程综述 gensim底层封装了Google的Word2Vec的c接口,借此实现了word2vec。使用gensim接口非常方便,整体流程如下: 1. 数据预处理(分词后的数据) 2. 数据读取 3.模型定义与训练...

muqiusangyang
45分钟前
1
0
Python爬虫之网络请求

urllib库中常用函数的使用 安装 urllib库是安装python时自带的一个库,不需要再另外安装; 使用 #!/usr/bin/python3# -*- coding:utf-8 -*-# @Time : 2018-11-10 21:25# @Author : M...

村雨1943
今天
4
0
Linux学习-1030(定时任务、任务管理、)

10.23 linux任务计划cron 10.24 chkconfig工具 10.25 systemd管理服务 10.26 unit介绍 10.27 target介绍 扩展 1. anacron http://blog.csdn.net/strikers1982/article/details/478722 2. xin......

wxy丶
今天
3
0
git push origin与git push -u origin master的区别

$ git push origin 上面命令表示,将当前分支推送到origin主机的对应分支。 如果当前分支只有一个追踪分支,那么主机名都可以省略。 $ git push 如果当前分支与多个主机存在追踪关系,那么这...

clin003
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部