Sentry实战 | 接入企业微信机器人

5,057 阅读3分钟

一、开通机器人权限

先找公司行政部门开通企业微信机器人权限。开通相关权限后,会发现此时就可以往公司企业微信群里添加相关机器人,如下图所示:

WX20210605-091742.png

创建一个机器人,叫日志监控机器人,专门用来进行 Sentry 的错误告警上报,如下图所示。

企业微信20210605092723.png

进入Sentry服务器,找到相应项目,并点击设置按钮。

企业微信20210605093858.png

将刚才生成的企业微信机器人的 Webhook 复制到 Sentry 服务器的相应项目中,点击保存,至此大功告成,是不是很激动!!!

企业微信20210605094342.jpg

点击测试插件按钮,发现企业微信机器人并没有收到相关日志提醒,咦,这是怎么回事,难道是复制的姿势不对?

造成这一问题的主要原因是 Sentry 调用 webhook 发送的数据报文格式和企业微信机器人要求的数据报文格式不一致造成的,如下所示:

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

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

Sentry发送的数据报文格式:

{
  id: '7',
  project: 'ii-admin-pro',
  project_name: 'ii-admin-pro',
  project_slug: 'ii-admin-pro',
  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 服务,将 Sentry 的数据报文做下转换,并按照企业微信机器人的数据报文格式进行发送。

二、搭建 Node 服务

笔者基于 egg.js 快速搭建了一个 Node 服务,路由配置如下:

企业微信20210605102704.png

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

'use strict';

const Controller = require('egg').Controller;
const request = require('../../utils/request');
const { SENTRY_HOOKS } = require('../../utils/const');
const { fmtDateTime, genProjectOwners } = require('../../utils/utils');

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

    const ROBOT_DATA = {
      msgtype: 'markdown',
      markdown: {
        content: `!!!前端项目<font color=\"warning\">${body.project_name}</font>发生错误:
> 错误原因: <font color=\"info\">${body.culprit}</font>
> 错误时间: <font color=\"info\">${fmtDateTime()}</font>
> 错误级别: <font color=\"info\">${body.level}</font>
> 错误链接: [查看日志](${body.url})
\n
请以下同事注意:${genProjectOwners(SENTRY_HOOKS[params.name].owners)}`,
      },
    };

    const result = await request({
      url: SENTRY_HOOKS[params.name].sentry_hook,
      method: 'POST',
      headers: {
        'content-type': 'application/json',
      },
      data: JSON.stringify(ROBOT_DATA),
    });

    this.ctx.body = {
      code: '0',
      data: result,
      msg: '提醒成功',
    };
  }
}

module.exports = SentryController;

utils/utils.js文件

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

  let 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}`;
};

/**
 * 生成项目负责人
 */
const genProjectOwners = (owners) => {
  return owners.map((item) => `<@${item}> `).join('');
};

module.exports = {
  fmtDateTime,
  genProjectOwners,
};

utils/const.js
主要用来存储配置常量,后续有新的项目,只需往常量文件中添加新的项目配置即可。 企业微信20210605103608.png

其中:

  • owners 存放的是企业微信用户的 userid,userid 即企业邮箱的前缀,举例:xiaoli@xxxx.com,userid 则是 xiaoli;

代码编写完后,接下来就是将项目部署上线了,笔者采用的是 pm2 来管理线上 Node 服务,运行pm2 deploy ecosystem.yaml production,将本地代码同步到线上,并重启 Node 服务(关于项目部署,不是本文重点,此处略过)。

将线上接口地址复制到 Sentry 服务器相应的 Webhooks 地址中,保存后点击测试插件按钮,测试日志监控机器人是否生效,如下所示: 企业微信20210605110231.png

这时,企业微信群成功收到 Sentry 发送过来的日志提醒,如下所示: 企业微信20210605110342.png

至此,大功告成!

注意事项:
开发过程中如果你的 Sentry 服务是部署在线上,不在本地局域网内,那么你本地在进行 Node 服务调试时是收不到 Sentry 发送的日志告警的,此时需要做内网穿透或者将你的node服务搭到线上,关于这一点要注意下!!!本人在这一问题曾卡壳一两天。

其他参考: