前端监控--通过钉钉自定义机器人发送告警消息

上一版本发布的只是单纯通过友盟监控,但是出现了错误我们也不会马上知道,毕竟友盟也没有即刻通知的功能,如果项目上线了,在测试没有覆盖到的场景下出现了线上bug,那我们开发人员也是不知道的,所以可以通过自定义一个钉钉机器人,来向群里发送报警消息,一旦项目出现了错误,直接上报到钉钉群,以便于更好的解决错误

先上报警图,然后再讲解怎么操作

这个是js错误报警,和上一篇的友盟报警类似,可以放在同一个地方进行上报,接口错误也是同理

这是接口错误报警

话不都说,直接开始

第一步:新建钉钉机器人,这个就不截图了,就是新建一个钉钉群,然后添加一个自定义机器人,但是需要注意的一点是,机器人在设置的时候,有一个安全设置,需要三选一,我都是直接选的自定义关键词,在这里需要注意,设置了自定义关键词之后,在向钉钉发送消息的时候,是需要将这个关键词包含在你发送的消息内部的,不然钉钉是接收不到你发送的信息的,群里也就不会报警

第二步:添加机器人之后,在前端项目怎么调用机器人呢?有会node的同学,可以自己写一个借口,在项目里面调用你自己的接口,通过你的接口转发,去调用钉钉机器人的 Webhook 地址。那么不会 node 的同学也不用慌,轮子也有大佬造好了,

在项目里安装  npm i dingtalk-robot-sender --save  这个模块,然后 按照官网链接的文档,一步步操作就可以了 官网链接:https://open-doc.dingtalk.com/microapp/serverapi3/iydd5h

第三步:因为需要先在本地进行调试,本地是http的,但是  Webhook 地址  是https 的,所以会包跨域,这个时候,需要去改动 webpack 配置了,不论是 cli2.xx 还是  cli3.xx 其实改动的属性都是一样的,只是改动的文件不一样,cli2.xx改动的是 build/webpack.config.dev.js  文件下的  devServer 属性,通过 proxy 配置一个代理

钉钉机器人的 Webhook  地址  https://oapi.dingtalk.com/robot/send?access_token=xxxxx  只有后面的token是不同的,所以我们在做代理的时候,可以按照下面的格式,这样在本地运行的时候,就会代理到正确地址不会报跨域了

proxy: {
  '/robot/send': {
    timeout: 1800000,                       // 请求时间
    target: 'https://oapi.dingtalk.com',    // 代理地址
    changeOrigin: true,                     // 是否允许跨域,为true代表允许
    secure: false                           // 是否允许访问 https,默认为true代表不允许,所以设置生false
  },
},

相比于 cli2.xx,3.xx的架子就是大改了,有兴趣的可以看看我的另外一篇介绍2.x 和 3.x 配置的博客,在3.x的项目中,直接找到根路径下的 vue.config.js文件,也是找到 devServer 配置 proxy 代理,但是有一个 不同就是 开启 https 访问

cli 3.x 的开启方式直接 设置属性 https:true 就可以了,secure: false 属性被移除了

下面就是一个完整的接入代码

同样是监控全局js错误,和友盟的代码可以做一个合并,同样是写在 main.js  文件内部

// 引入钉钉机器人报警
const ChatBot = require('dingtalk-robot-sender');

// 引入格式化时间,获取设备信息
import { format, initDeviceInfo, getBrowserInfo, detectOS, digits } from '../../../lib/external/config.js';


Vue.config.errorHandler = function (err, vm, info) {
  // err 就是错误信息
  // vm相当于this实例
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
  console.log(err, vm, info, 'err, vm, info')

  let errMsg = `
    info: ${err}
    --apName : 数据中台
    --url: ${window.location.href}
    --browser:${detectOS()}-${digits()} ${getBrowserInfo()}
    --time: ${format('yyyy-MM-dd hh:mm:ss')}
    `

  // 区分上报环境
  if (_czc && process.env.NODE_ENV == 'development') {

    //错误捕获上报到友盟
    console.log(_czc, '_czc')

    _czc.push(["_trackEvent", "JS错误", "异常抛出", errMsg, 1]);

    // 直接使用 webhook
    const robot = new ChatBot({
      webhook: '/robot/send?access_token=xxxxxxxxx'
    });

    // 规定发送的消息的类型和参数
    let textContent = {
      "msgtype": "text",
      "text": {
        "content": `错误:${errMsg}`   // 注意了,字符串里面的错误汉字,其实就是你在钉钉报警设置的自定义字段,两个地方需要相同,否则不会发送到群里
      },
    }

    // 机器人发送消息
    robot.send(textContent)
      .then((res) => {
        // TODO
        console.log(res)
      });
  }
}

这就是 config.js  文件内的几个工具函数,用来获取当前设备,浏览器信息,以及格式化时间

//避免引入新的js包,自己对formate进行简易封装
export function format(fmt) {
  //author: meizz
  var o = {
    "M+": new Date().getMonth() + 1, //月份
    "d+": new Date().getDate(), //日
    "h+": new Date().getHours(), //小时
    "m+": new Date().getMinutes(), //分
    "s+": new Date().getSeconds(), //秒
    "q+": Math.floor((new Date().getMonth() + 3) / 3), //季度
    S: new Date().getMilliseconds() //毫秒
  };
  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (new Date().getFullYear() + "").substr(4 - RegExp.$1.length));
  for (var k in o)
    if (new RegExp("(" + k + ")").test(fmt))
      fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
  return fmt;
};


/**
 * 初始化设备信息
 */
export function initDeviceInfo() {
  let _deviceInfo = ""; //设备信息
  console.log(navigator, 'navigator')
  if (navigator == null) {
    _deviceInfo = "PC";
  }
  if (navigator.userAgent != null) {
    var su = navigator.userAgent.toLowerCase(),
      mb = ["ipad", "iphone os", "midp", "rv:1.2.3.4", "ucweb", "android", "windows ce", "windows mobile"];

    // 开始遍历提前设定好的设备关键字,如果设备信息中包含关键字,则说明是该设备
    for (var i in mb) {
      if (su.indexOf(mb[i]) > 0) {
        _deviceInfo = mb[i];
        break;
      }
    }
  }
  return _deviceInfo
}

/**
 * 获取浏览器的信息
 */
export function getBrowserInfo() {
  var output = "other";
  // Opera 8.0+
  var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(" OPR/") >= 0;
  if (isOpera) {
    output = "Opera";
  }
  // Firefox 1.0+
  var isFirefox = typeof InstallTrigger !== "undefined";
  if (isFirefox) {
    output = "Firefox";
  }
  // Safari 3.0+ "[object HTMLElementConstructor]"
  var isSafari =
    /constructor/i.test(window.HTMLElement) ||
    (function (p) {
      return p.toString() === "[object SafariRemoteNotification]";
    })(!window["safari"] || (typeof safari !== "undefined" && safari.pushNotification));
  if (isSafari) {
    output = "Safari";
  }
  // Internet Explorer 6-11
  var isIE = /*@cc_on!@*/ false || !!document.documentMode;
  if (isIE) {
    output = "IE";
  }
  // Edge 20+
  var isEdge = !isIE && !!window.StyleMedia;
  if (isEdge) {
    output = "Edge";
  }
  // Chrome 1 - 79
  var isChrome = !!window.chrome && navigator.userAgent.indexOf("Chrome") !== -1;
  if (isChrome) {
    output = "Chrome";
  }
  // Edge (based on chromium) detection
  var isEdgeChromium = isChrome && navigator.userAgent.indexOf("Edg") !== -1;
  if (isEdgeChromium) {
    output = "EdgeChromium";
  }
  return output;
};

export function detectOS() {
  var userAgent = window.navigator.userAgent,
    platform = window.navigator.platform,
    macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"],
    windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"],
    iosPlatforms = ["iPhone", "iPad", "iPod"],
    os = null;

  if (macosPlatforms.indexOf(platform) !== -1) {
    os = "Mac OS";
  } else if (iosPlatforms.indexOf(platform) !== -1) {
    os = "iOS";
  } else if (windowsPlatforms.indexOf(platform) !== -1) {
    os = "Windows";
  } else if (/Android/.test(userAgent)) {
    os = "Android";
  } else if (!os && /Linux/.test(platform)) {
    os = "Linux";
  }

  return os;
};

export function digits() {
  var sUserAgent = navigator.userAgent;
  var is64 = sUserAgent.indexOf("WOW64") > -1;
  if (is64) {
    return "64bit";
  } else {
    return "32bit";
  }
};

同理,对于接口报错,也可以和友盟的接口错误上报合并到一起,具体代码就不放了复制一遍过去改几个参数就好了

但是这个监控存在局限性,这个是写在项目中的,还要在项目中新增许多配置,我如果项目多了,配置起来也会很麻烦,所以我想的是,最后打包,做成 cdn 引入,只需要在项目中 调用暴露出来的 api,传当前项目名,传监控cdn的版本等等其他信息,而不用每个项目都去配置一大串。这个有待后续优化,现在只是做了一个大概的模子,要写成 cdn  模式的,需要考虑到的东西估计比较多,

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值