zoukankan      html  css  js  c++  java
  • 前端异常---日志上报服务搭建

    前端异常---日志上报服务搭建

    关于前端异常分类与捕获可以看看我的这篇文章
    JavaScript 网页异常捕获

    既然异常已经捕获到了,那我们怎么处理呢,如何上报,需要上报哪些内容?


    一、日志分类


    1、一般日志分类等级

    log、debug、info、warn、error
    

    2、分场景使用日志上报类型

    log:    记录流程信息
    debug: 记录调试关键信息
    info:  记录业务功能点,是否触发成功或者失败
    warn:   页面警告信息
    error: 页面错误或者业务异常信息
    

    3、日志上报信息附带信息

    1、用户id、session、用户名
    2、当前错误信息
    3、可以用来重现、推断当前错误发生的信息
    4、上报时间
    5、日志等级
    等等
    

    4、日志上报策略

    1、达量上传,设置一个缓存数量,到达即上报。因为不能一发生错误就要上报,会影响用户的网络。
    2、日志埋点处各自有各自的上报等级。
    需要有一个总配置地方,配置当前的上报等级
    这样各处埋点可以判断当前需要上报的日志等级,等级小于设置值的话,不可上报。
    3、本地缓存若暂存过多,需要删除前面的数据
    4、抽样上报
    5、设置缓存有效时间
    等等
    

    上报之后,接下来的步骤就是在服务端收集分析归类展示,所以需要我们搭建一整套日志解析系统

    今天我们来尝试使用 badjs 相关项目,搭建一整套日志分析系统


    二、badjs 服务安装


    1、前期预备工作

    为了快速搭建,我们统一使用 docker 安装

    备注:windows 环境使用 docker,需要安装 Docker Desktop

    a、mysql 安装

    docker 安装 mysql

    备注:mysql 安装好后,需要从 badjs-web (需要先把项目下载下来)项目中的 db 目录下

    使用 create.sql 初始化 web 相关的数据库

    b、mongodb 安装

    docker 安装 mongo
    备注:不可设置密码


    2、项目安装

    github 克隆项目到本地

    git clone https://github.com/BetterJS/badjs-installer
    

    子项目下载以及依赖安装

    // 克隆下载 badjs-acceptor、badjs-mq、badjs-storage、badjs-web 项目
    yarn clone
    
    // 安装各项目的依赖
    yarn install
    

    3、修改配置项

    1、修改 badjs-acceptor 项目的 project.debug.json/project.json

    注意:这里是日志上报的地方,客户端初始化 badjs-report 时候需要设置的 url 属性即是这里的服务地址

    http://{badjs-acceptor:port}/badjs

    // 修改 port 属性: 从 80 改为 8083; 
    // 因为 node 默认没有 80 端口的权限,需要你使用管理员权限才可以使用
    {
        "port": 8083
    }
    

    2、修改 badjs-web 项目的 project.debug.json/project.json

    // 修改 mysql 属性,配置我们 docker 安装好的 mysql 用户密码与端口
    {
        "mysql" : {
            "url" : "mysql://root:123456@localhost:3306/badjs"
        }
    }
    

    4、启动项目

    // 启动各项目
    yarn start
    

    查看 badjs-web 的启动端口,访问 http://localhost:port 可以看到日志后台管理服务页面


    三、badjs 各模块关系


    1、badjs-acceptor 接受客户端上报的日志

    badjs-acceptor 收到日志上报,发送到 badjs-mq
    package.json 中配置 dispatcher 分发属性, 表示向 badjs-mq 请求的信息:如请求端口(10001)
    

    2、badjs-mq 消息队列,保证消息有序稳定被接受

    badjs-mq 接收 badjs-acceptor 的请求
    package.json 中配置 acceptor 接收属性, 表示用来接收信息所配置的接口信息:如端口(10001)。
    
    badjs-mq 再分发到 badjs-storage
    package.json 中配置 dispatcher 分发属性, 表示向 badjs-storage 请求的信息:如端口(10000)
    

    3、badjs-storage 存储模块

    badjs-storage: 接收来自 badjs-mq 的请求,再写入到 mongodb
    package.json 中配置 acceptor 接收属性, 表示用来接收信息所配置的接口信息:如端口(10000)
    

    4、badjs-web 日志后台管理系统

    badjs-web 查询日志存储,分类查看日志信息,解析日志内容
    package.json 中配置 acceptor 接收属性, badjs-acceptor 可请求的端口
    package.json 中配置 storage 存储属性, 查询 mongodb 数据
    package.json 中配置 mysql 数据库属性, 查询 mysql 数据
    等等
    

    四、上报日志插件 badjs-report

    badjs-report 重写了 window.onerror 来捕获错误

    1、安装

    yarn add badjs-report
    

    2、初始化

    import badjs from 'badjs-report'
    
    badjs.init({
        // 必须配置项
        id: 1 // 此 id 为 badjs-web 启动后,申请的项目的 id,上报的日志根据该 id 区分业务模块
        url: 'http://badjs-acceptor启动后的地址', // 日志上报到的地方
    
        // 选择配置
        uin: 123, // 指定用户的 id (该插件默认读取 qq uin)
        delay: 1000, // 延迟多少毫秒,合并缓冲区中的上报(默认 1000)
        ignore: [/Script error/i], // 忽略某个错误,遇到该错误不进行上报
        random: 1, // 抽样上报, 值可以设置 0-1 之间。1 表示 100% 上报(默认为 1)
        repeat: 5, // 重复上报次数(对于同一个错误超过多少次不上报;避免单个用户同一错误上报过多的情况)
        onReport: function(id, errObj) {}, // 上报日志之后的回调。id 为上报的 id,errorObj 为上报的错误对象
        submit: function(url) {}, // 覆盖原来的上报方式,原来是使用 new Image() 形式上报,可以修改成自己想要上报的方式,比如使用 post 内部构造好的 url
        ext: {}, // 扩展属性,后端做扩展处理属性。设置了 ext 的值,就会作为 'ext=设置的值' 合并到构造好的上报 url 中
        offlineLog: false, // 是否开启离线日志(默认不开启为 false)
        offlineLogExp: 5 // 离线有效时间(默认最近5天)
    })
    

    3、手动上报

    a、badjs.report('error msg')
    b、badjs.report({
        msg: 'error msg', // 需要上报的错误信息
        target: 'error.js', // 发生错误的 js 文件
        rowNum: 1, // 发生错误的行数
        colNum: 2 // 发生错误的列数
    })
    

    4、延迟上报

    暂存

    badjs.push('error msg')
    badjs.push({
        msg: 'error msg', // 需要上报的错误信息
        target: 'error.js', // 发生错误的 js 文件
        rowNum: 1, // 发生错误的行数
        colNum: 2 // 发生错误的列数
    })
    

    立即上报

    badjs.report({
        msg: 'error msg', // 需要上报的错误信息
        target: 'error.js', // 发生错误的 js 文件
        rowNum: 1, // 发生错误的行数
        colNum: 2 // 发生错误的列数
    })
    

    5、上报离线日志

    badjs.reportOfflineLog()
    

    五、项目使用示例

    import BJ_REPORT from 'badjs-report'
    import Vue from 'vue'
    
    // 环境ID枚举
    let ENV_ID_ENUM = {
        DEV: 1,
        SIT: 2,
        UAT: 3,
        PRO: 4
    }
    let curEnv = '',
        origin = window.location.origin
    if (origin.indexOf('dev.xxx.com') > -1) {
        // http://dev.xxx.com
        // DEV 环境
        curEnv = 'DEV'
    } else if (origin.indexOf('sit.xxx.com') > -1) {
        // http://sit.xxx.com
        // SIT 环境
        curEnv = 'SIT'
    } else if (origin.indexOf('uat.xxx.com') > -1) {
        // http://uat.xxx.com
        // UAT 环境
        curEnv = 'UAT'
    } else if (origin.indexOf('m.xxx.com') > -1) {
        // http://pro.xxx.com
        // PRO 环境
        curEnv = 'PRO'
    }
    let envID = ENV_ID_ENUM[curEnv] || ENV_ID_ENUM.DEV
    
    // 初始化日志上报插件
    BJ_REPORT.init({
        id: envID, // 不指定 id 将不上报,
        url: 'http://{badjs-acceptor:port}/badjs'
    })
    
    // 初始化项目时,可以暴露一个全局的 vm 实例,方便上传需要的信息
    window.rootvm = new Vue({}) // 初始化项目
    
    // 初始化监听异常
    init(window.rootvm)
    function init(rootInstance) {
        Vue.config.errorHandler = function(err, curInstance, info) {
            // vm 为抛出异常的 Vue 实例
            // info 为 Vue 特定的错误信息,比如错误所在的生命周期钩子
            let {
                message, // 异常信息
                // name, // 异常名称
                // script, // 异常脚本url
                line, // 异常行号
                column, // 异常列号
                stack // 异常堆栈信息
            } = err
            log(message, stack, line, column, curInstance)
            console.log('vue errorHandler :>> ', err, curInstance, info)
        }
        window.addEventListener(
            'error',
            e => {
                let { colno, lineno, message, filename } = e
                log(message, filename, lineno, colno, rootInstance)
                console.log('addEventListener error 捕获阶段>>>异常:', e)
            },
            true
        )
        window.addEventListener('unhandledrejection', function(e) {
            // e.preventDefault(); // 阻止异常向上抛出
            let { reason } = e
            log(JSON.stringify(reason), '', '', '', rootInstance)
            console.log('Promise 异常 unhandledrejection :', e)
        })
    }
    
    function log(msg, target, rowNum, colNums, vminstance) {
        let msgs = `***[${msg}]***`,
            state = (vminstance && vminstance.$store && vminstance.$store.state) || {}
    
        // 用户信息
        if (state.userInfo) {
            let { phoneNumber, userId } = state.userInfo
            msgs += `***[phone:${phoneNumber}--userId:${userId}]***`
        }
        // 路由信息
        let { name, fullPath } = (vminstance && vminstance.$route) || {}
        msgs += `***[router-name: ${name} -- router-fullpath: ${fullPath}]***`
    
        BJ_REPORT.report({
            msg: msgs,
            target,
            rowNum,
            colNums
        })
    }
    
  • 相关阅读:
    【Java&Android开源库代码分析】のandroid-async-http の开盘
    静态库和动态库
    抽象工厂
    XXX系统发展综述(SSH+Jquery EasyUI)
    android 控制手机的体积的大小 切换音效模式
    中国误区,你还抓?
    PID教程
    setsockopt的作用
    【ThinkingInC++】66、pointer Stash的使用
    jbpm入门样例
  • 原文地址:https://www.cnblogs.com/linjunfu/p/14155199.html
Copyright © 2011-2022 走看看