XXL-JOB学习笔记-新增企业微信告警通知

news/2024/5/19 0:59:08 标签: java, spring boot, xxl-job, 企业微信
xxl-job默认的告警通知方式是发送邮件,工作中不易及时的收到通知并作出响应,所以想要调整下告警的通知方式,查阅文档资料,发现可以扩展xxl-job的源码实现支持。
主要思路就是根据xxl-job现有的告警机制,扩展实现企业微信机器人的告警功能,接下来就记录下xxl-job新增企业微信告警通知功能。
  • 从官方网站上下载xxl-job源码,导入IDEA。
    官方地址:https://github.com/xuxueli/xxl-job 或 https://gitee.com/xuxueli0323/xxl-job
  • xxl-job现有的告警功能。可以发现只要实现JobAlarm这个接口就可以了。
java">@Component
public class JobAlarmer implements ApplicationContextAware, InitializingBean {

    private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);

    private ApplicationContext applicationContext;

    private List<JobAlarm> jobAlarmList;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
        if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
            jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());
        }
    }

    /**
     * job alarm
     *
     * @param info
     * @param jobLog
     * @return
     */
    public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
        boolean result = false;
        if (jobAlarmList!=null && jobAlarmList.size()>0) {
            result = true;  // success means all-success
            for (JobAlarm alarm: jobAlarmList) {
                boolean resultItem = false;
                try {
                    resultItem = alarm.doAlarm(info, jobLog);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
                if (!resultItem) {
                    result = false;
                }
            }
        }
        return result;
    }

}
  • 扩展实现企业微信机器人的告警功能。
    企业微信终端某个群组添加机器人之后,创建者可以在机器人详情页看到该机器人特有的webhookurl。开发者可以向这个地址发起HTTP POST请求,即可实现给该群组发送消息。相关资料可以参考:https://developer.work.weixin.qq.com/document/path/91770
    后续可能还会有其他告警通知的需求(比如钉钉告警通知等),就先抽取一个类出来,方便后续扩展。
java">public abstract class AbstractJobAlarm implements JobAlarm {

    protected static final Logger logger = LoggerFactory.getLogger(AbstractJobAlarm.class);

    protected static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    protected RestTemplate restTemplate = new RestTemplate();

    public abstract String containsKeyword();

    public abstract String genJobAlarmRequestUrl(String keyword);

    public abstract Object genJobAlarmRequestBody(XxlJobInfo xxlJobInfo, XxlJobLog xxlJobLog);

    @Override
    public boolean doAlarm(XxlJobInfo xxlJobInfo, XxlJobLog xxlJobLog) {
        if (null == xxlJobInfo) {
            return true;
        }
        String alarmEmail = xxlJobInfo.getAlarmEmail();
        if (null == alarmEmail || "".equals(alarmEmail) || !alarmEmail.contains(containsKeyword())) {
            return true;
        }
        boolean alarmResult = true;
        Object jobAlarmRequestBody = genJobAlarmRequestBody(xxlJobInfo, xxlJobLog);
        String[] keywordArray = alarmEmail.split(",");
        for (int i = 0, len = keywordArray.length; i < len; i++) {
            try {
                String jobAlarmRequestUrl = genJobAlarmRequestUrl(keywordArray[i]);
                logger.info("job alarm request url {} body {}", jobAlarmRequestUrl, jobAlarmRequestBody);
                restTemplate.postForEntity(jobAlarmRequestUrl, jobAlarmRequestBody, Object.class);
            } catch (Exception e) {
                logger.error(">>>>>>>>>>> xxl-job, job fail alarm send error, job log id:{}", xxlJobLog.getId(), e);
                alarmResult = false;
            }
        }
        return alarmResult;
    }

    protected String buildJobAlarmContentV1(XxlJobInfo xxlJobInfo, XxlJobLog xxlJobLog) {
        StringBuilder content = new StringBuilder();
        content.append("【告警信息】\n");
        content.append("负责人: ").append(buildAuthor(xxlJobInfo.getAuthor())).append("\n");
        content.append("描述: ").append(xxlJobInfo.getJobDesc()).append("\n");
        content.append("JOB_ID: ").append(xxlJobLog.getJobId()).append("\n");
        content.append("JOB_GROUP: ").append(xxlJobLog.getJobGroup()).append("\n");
        content.append("执行器名称: ").append(xxlJobInfo.getExecutorHandler()).append("\n");
        content.append("执行器IP: ").append(xxlJobLog.getExecutorAddress()).append("\n");
        content.append("任务参数: ").append(xxlJobLog.getExecutorParam()).append("\n");
        content.append("告警时间: ").append(SDF.format(new Date())).append("\n");
        content.append("LOG_ID: ").append(xxlJobLog.getId()).append("\n");
        Date triggerTime = xxlJobLog.getTriggerTime();
        if (null != triggerTime) {
            content.append("TRIGGER_TIME: ").append(SDF.format(triggerTime)).append("\n");
        }
        String triggerMsg = xxlJobLog.getTriggerMsg();
        if (null != triggerMsg && !"".equals(triggerMsg.trim())) {
            content.append("TRIGGER_MSG: ").append(triggerMsg.replace("<br>", "\n")).append("\n");
        }
        Date handleTime = xxlJobLog.getHandleTime();
        if (null != handleTime) {
            content.append("HANDLE_TIME: ").append(SDF.format(handleTime)).append("\n");
        }
        String handleMsg = xxlJobLog.getHandleMsg();
        if (null != handleMsg && !"".equals(handleMsg.trim())) {
            content.append("HANDLE_MSG: ").append(handleMsg).append("\n");
        }
        return content.toString();
    }

    private String buildAuthor(String author) {
        return null == author || "".equals(author) ? author : String.join(",",
            Arrays.stream(author.split(",")).map(v -> "@" + v).collect(Collectors.toList()));
    }

}
java">public class QyWeiXinJobAlarm extends AbstractJobAlarm {

    @Value("${qyweixin.robot.webhook.url.prefix:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?}")
    private String webhookUrlPrefix;

    @Override
    public String containsKeyword() {
        return "key";
    }

    @Override
    public String genJobAlarmRequestUrl(String keyword) {
        return webhookUrlPrefix + keyword;
    }

    /**
     * 
     * @param xxlJobInfo
     * @param xxlJobLog
     * @return
     */
    @Override
    public Object genJobAlarmRequestBody(XxlJobInfo xxlJobInfo, XxlJobLog xxlJobLog) {
        HashMap<String, Object> requestBodyMap = new HashMap<>();
        try {
            // 获取执行日志信息
            ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(xxlJobLog.getExecutorAddress());
            if (null != executorBiz) {
                ReturnT<LogResult> resultReturnT = executorBiz.log(new LogParam(
                    xxlJobLog.getTriggerTime().getTime(), xxlJobLog.getId(), 1));
                if (null != resultReturnT) {
                    LogResult logResult = resultReturnT.getContent();
                    if (null != logResult && null != logResult.getLogContent()) {
                        logger.info("return result log {}", logResult.getLogContent());
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        // 消息类型
        requestBodyMap.put("msgtype", "text");
        HashMap<String, Object> textMap = new HashMap<>();
        textMap.put("content", buildJobAlarmContentV1(xxlJobInfo, xxlJobLog));
        // 设置是否@指定人
        String author = xxlJobInfo.getAuthor();
        if (null != author && !"".equals(author)) {
            List<String> authors = Arrays.stream(author.split(",")).collect(Collectors.toList());
            //authors.add("@all");
            textMap.put("mentioned_list", authors);
            textMap.put("mentioned_mobile_list", authors);
        }
        requestBodyMap.put("text", textMap);
        return requestBodyMap;
    }

}
  • 自此,企业微信告警通知扩展实现完成,重新打包部署即可。没有调整修改前端的界面,所以只需要在原先的邮件文本框输入key=xxxxxx,key=xxxxxx即可。

http://www.niftyadmin.cn/n/5308659.html

相关文章

学习笔记——C++运算符之逻辑运算符

作用&#xff1a;用于根据表达式的真值返回真值或假值 逻辑运算符有以下符号&#xff1a; #include<bits/stdc.h> using namespace std; int main(){// 逻辑运算符 非 !int a10;//在c中&#xff0c;除了0均是真 cout<<!a<<endl;//0 cout<<!!a<<…

Flume基础知识(十):Flume 聚合实战

1&#xff09;案例需求&#xff1a; hadoop100上的 Flume-1 监控文件/opt/module/group.log&#xff0c; hadoop101上的 Flume-2 监控某一个端口的数据流&#xff0c; Flume-1 与 Flume-2 将数据发送给 hadoop102 上的 Flume-3&#xff0c;Flume-3 将最终数据打印 到控制台。…

2024年,Web3技术的“iPhone时刻”会出现吗?

出品&#xff5c;欧科云链研究院 关于2024年的Web3市场&#xff0c;大多数人目前是持乐观态度的。随着宏观政策稳定&#xff0c;美国和香港地区不断释放加密资产现货ETF的利好&#xff0c;叠加铭文热潮及减半周期临近&#xff0c;市场对Web3及加密资产的兴趣正持续上涨。年后的…

Embedded-Project项目介绍

Embedded-Project项目介绍 Server后端项目后端启动连接数据库启动时可能遇到的问题架构介绍 web前端项目前端启动启动时可能遇到的问题架构介绍 前后端分离开发流程 项目地址&#xff1a; https://github.com/Catxiaobai/Embedded-Project Server后端项目 系统后端项目&#…

C#不会循环响应的Action设计与实现

目录 一、简述二、测试代码三、测试的输出四、核心代码五、其它 一、简述 特点&#xff1a; 不光是能防止直接的死循环调用&#xff1b;还能防止间接的死循环调用&#xff1b;还支持对不同参数判定&#xff0c;不同参数的调用可以不当循环调用&#xff1b; 消息事件系统中必…

【GitHub】-design-pattern-extend(设计模式扩展)

写在前面 偶然间看到一篇文章 《Java 中保持扩展性的几种套路和实现》&#xff0c;写的不错&#xff0c;但是类图画的差了点儿意思。于是&#xff0c;自己动手画了画&#xff0c;对其中的内容作了一些调整&#xff0c;对包做了进一步划分&#xff0c;便于理解消化。以下是对Git…

vue项目接入滑动验证码

前言 本文教你基于Node.js环境&#xff0c;在vue项目中如何接入KgCapctah。 准备工作 访问凯格行为验证码官网&#xff0c;注册账号后登录控制台&#xff0c;访问“无感验证”模块&#xff0c;申请开通后系统会分配给应用一个唯一的AppId、AppSecret。凯格提供后端SDK来校验…

【大数据进阶第三阶段之Hive学习笔记】Hive常用命令和属性配置

目录 1、Hive安装 2、HiveJDBC访问 2.1、启动hiveserver2服务 2.2、连接hiveserver2服务 2.3、注意 3、Hive常用交互命令 3.1、“-e”不进入hive的交互窗口执行sql语句 3.2、“-f”执行脚本中sql语句 4、Hive其他命令操作 4.1、退出hive窗口 4.2、在hive cli命令窗口…