Sentry接入企业微信消息通知

2,768 阅读2分钟

一、背景

公司客户端项目是基于Electron开发的,里面集成了一些第三方的插件和库,经常会遇到一些兼容性和性能问题,目前是通过用户反馈,运维去远程协助,处理不了的就会提bug给开发人员排查,部分问题测试又难以重现,所以处理起来很头疼。于是就想到要输出错误日志文件和错误告警上报,然后把错误信息发送到企业微信。方便开发定位和排查问题。

二、开通机器人权限

首先,我们要在企业微信群里创建一个机器人,叫日志监控机器人,专门用来进行 Sentry 的错误告警上报,如下图所示

image.png

因为Sentry调用webhook发送的数据报文格式和企业微信机器人要求的数据报文格式不一致,所以需要搭建Node服务,将Sentry的数据报文做下转换,并按照企业微信机器人的数据报文格式进行发送。

企业微信机器人要求的数据报文格式:

{
    "msgtype": "text",
    "text": {
        "content": "广州今日天气:29度,大部分多云,降雨概率:60%",
        "mentioned_list":["wangqing","@all"],
        "mentioned_mobile_list":["13800001111","@all"]
    }
}

Sentry发送的数据报文格式:

{
  id: '7',
  project: 'xx',
  project_name: 'xx',
  project_slug: 'xx',
  logger: null,
  level: 'error',
  culprit: 'raven.scripts.runner in main',
  message: 'This is an example Python exception',
  url: 'http://sentry.xxxxxxx.com/organizations/sentry/issues/7/?referrer=webhooks_plugin',
  triggering_rules: [],
  event: {
    event_id: 'f602ac321ee04bc28a20c9f4d446ef48',
    level: 'error',
    version: '5',
    type: 'default',
    logentry: {
      formatted: 'This is an example Python exception',
      message: null,
      params: null
    },
    logger: '',
    modules: { 'my.package': '1.0.0' },
    platform: 'python',
    timestamp: 1622734089.769465,
    received: 1622734089.7702,
    environment: 'prod',
    user: {
      id: '1',
      email: 'sentry@example.com',
      ip_address: '127.0.0.1',
      username: 'sentry',
      name: 'Sentry',
      geo: [Object]
    },
    request: {
      url: 'http://example.com/foo',
      method: 'GET',
      data: [Object],
      query_string: [Array],
      cookies: [Array],
      headers: [Array],
      env: [Object],
      inferred_content_type: 'application/json',
      fragment: null
    },
    ...
  }
}

三、搭建 Node 服务

基于egg.js快速搭建一个Node服务

npm init egg-message-notification --type=saimple
npm i

启动项目

npm run dev
open http://localhost:7001

看到下图说明启动成功了

image.png

路由配置如下

image.png

在app/controller/sentry.js文件中创建 SentryController,用来负责数据报文的转换,代码如下:

'use strict';

const Controller = require('egg').Controller;
const axios = require('axios');
const CircularJSON = require('circular-json');

/**
 * 对当前时间进行格式化
 */
const fmtDateTime = () => {
  const date = new Date();

  const year = date.getFullYear();
  let month = date.getMonth() + 1;
  let hour = date.getHours();
  let min = date.getMinutes();

  month = month < 10 ? `0${month}` : month;
  hour = hour < 10 ? `0${hour}` : hour;
  min = min < 10 ? `0${min}` : min;

  return `${year}-${month}-${date.getDate()} ${hour}:${min}`;
};

class SentryController extends Controller {
  /**
   * 接收Sentry发送过来的Webhook
   */
  async recvSentryWebhook() {
    const { ctx } = this;
    const { request: { body } } = ctx;
    const error = body.data && body.data.error || {};

    ctx.logger.info(body);

    const ROBOT_DATA = {
      msgtype: 'markdown',
      markdown: {
        content: `<font color=\"warning\">${error.release || error.extra._productName}</font>发生错误:
                  > 错误原因: <font color=\"info\">${error.title}</font>
                  > 错误时间: <font color=\"info\">${fmtDateTime()}</font>
                  > 错误级别: <font color=\"${error.level === 'fatal' ? '#FF0000' : '#008000'}\">${error.level}</font>
                  > 错误链接: [查看日志](${error.web_url})`,
      },
    };

    const result = await axios({
      url: '企业微信机器人webhook地址',
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      data: JSON.stringify(ROBOT_DATA),
    });

    ctx.body = {
      status: 'success',
      data: CircularJSON.stringify(result),
      msg: '提醒成功',
    };
  }
}

module.exports = SentryController;

最后,别忘了配置csrf,在config/config.default.js添加如下代码

config.security = {
  csrf: {
    enable: false,
  },
};

四、部署Node服务

我的做法是把代码提交到git仓库,然后再服务器clone下来,安装依赖,执行npm run start命名启动服务,看到下图就说明启动成功了

image.png

五、添加内部集成

image.png

image.png

image.png

六、企业微信信息通知

image.png