jsoup登录日志平台后调企业微信机器人自动发送错误日志告警

一、需求:错误日志Top10告警发送

二、需求分解

  1. jsoup实现登录,获取到cookie和token等用户鉴权信息
  2. 获取接口相应的key值
  3. 调用日志平台错误日志Top榜接口,查询到结果集
  4. 调用企业微信机器人发送消息接口
  5. 加上定时任务,可以实现定时发送错误日志告警的功能

定时任务高度设置1小时(根据实际需要)执行一次,可以实现自动巡检错误日志的功能。以便及时发现生产问题

jsoup是java的爬虫框架,可以爬取网页数据,这里没有重点使用,只是做了个登录功能。后续可以专门它写一份爬虫的程序。。

  <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.12.1</version></dependency>
package com.smy.cbs.task;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.smy.cbs.util.RetryUtil;
import com.smy.smyx.scheduler.dto.TaskRequest;
import com.smy.smyx.scheduler.dto.TaskResponse;
import com.smy.smyx.scheduler.service.TaskService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import javax.net.ssl.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;/*** @author youlu* @ClassName logCenterTask* @Date 2023/11/22 17:14* @Version V1.0**/
@Slf4j
@Service("logCenterTask")
public class LogCenterTask implements TaskService {@Resourceprivate RetryUtil retryUtil;@Value("${log.usename:aaaa}")public String USER_NAME;@Value("${log.password:bbbbbb}")public String PASSWORD;@Value("${log.content.warn.max:24000000}")public int maxCount;//达到阈值则告警@Value("${log.content.filter.content:输入要过滤的内容有英文逗号隔开}'.split(',')}")public List<String> filterContent = Lists.newArrayList();//过滤内容@Value("${log.content.length:240}")public int SUB_CONTENT_LENGTH = 240;//截取报错内容字符串长度@Value("${log.title.length:20}")public int SUB_TITLE_LENGTH = 20;//截取报错类型字符串长度@Value("${log.period.hour:24}")public int PERIOD_HOUR;//24小时内的错误日志@Value("#{'${log.search.system:cbs_core,rls_core,uts_core,adv_core}'.split(',')}")public List<String> SEARCH_SYSTEM;//查询的系统@Value("#{'${log.wx.url:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=aaaaaa,https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=bbbbbbbb3}'.split(',')}")public String WX_ROBOT_URL;public static final String LOG_CENTER_BASE_URL = "https://log_center.xxx.com/api/";public static String X_Csrf_Token = "";public static String COOKIE = "";public static String id = "";public static final String TEMPLATE = "{\"msgtype\":\"markdown\",\"markdown\":{\"content\":\"%s\"}}";public static final String QUERY_TEMPLATE = "{\n" +"  \"app\": \"system\",\n" +"  \"source\": \"other\",\n" +"  \"query\": \"repo=\\\"smy_%s\\\" origin=\\\"*\\\" AND \\\"ERROR\\\"\\n| where level=\\\"ERROR\\\"\\n| eval err_type=arr_index(split(arr_index(split(_raw, \\\" - \\\"), 1), \\\"\\\\d+\\\"), 0)\\n| stats count() as num by err_type\\n| sort 10 by num\\n| join type=inner err_type [\\n  repo=\\\"smy_%s\\\" origin=\\\"*\\\" AND \\\"ERROR\\\"\\n  | where level=\\\"ERROR\\\"\\n  | eval err_type=arr_index(split(arr_index(split(_raw, \\\" - \\\"), 1), \\\"\\\\d+\\\"), 0)\\n  | fields + err_type, _raw\\n  | dedup err_type\\n]\\n| rename _raw as 原始日志, num as 统计, err_type as 错误类型\",\n" +"  \"mode\": \"smart\",\n" +"  \"preview\": false,\n" +"  \"collectSize\": -1,\n" +"  \"timeout\": 1000,\n" +"  \"sorts\": []\n" +"}";@SneakyThrows@Overridepublic TaskResponse execute(TaskRequest request) {//1.模拟登录 jsoupjsoupLogin();for (String systemName : SEARCH_SYSTEM) {try {Thread.sleep(1000);//2.获取keyString id = getKey(systemName);Thread.sleep(8000);List<Map<String, Object>> logCenterList = retryUtil.doRetry(4, () -> {//3.获取查询结果List<Map<String, Object>> contentList = getContentList(systemName, id);if (CollectionUtils.isEmpty(contentList)) {Thread.sleep(8000);throw new Exception(systemName + "未查询到数据,需要重试!");}return contentList;}, systemName + "获取日志数据");//4.调微信发送短信sendWxMessage(systemName, id, logCenterList);} catch (Exception e) {log.error("{}发送错误日志告警出现异常e:{}", systemName, e);}}return new TaskResponse(TaskResponse.SUCCESS, "logCenter任务完成");}public String getKey(String systemName) {Date endDate = new Date();Date startDate = DateUtil.offsetHour(endDate, -PERIOD_HOUR);//请求参数JSONObject paramJson = JSON.parseObject(String.format(QUERY_TEMPLATE, systemName, systemName));paramJson.put("startTime", startDate.getTime());paramJson.put("endTime", endDate.getTime());HttpResponse execute = HttpRequest.post(LOG_CENTER_BASE_URL + "jobs")//设置请求头(可任意加).header("X-Csrf-Token", X_Csrf_Token).header("Cookie", COOKIE).header("Content-Type", "application/json").header("Connection", "keep-alive")//请求参数.body(paramJson.toJSONString()).timeout(40000).execute();String body1 = execute.body();String id = JSON.parseObject(body1).getString("id");return id;}public List<Map<String, Object>> getContentList(String systemName, String id) {String url = LOG_CENTER_BASE_URL + "jobs/" + id + "/results";HttpResponse execute = HttpRequest.get(url)//设置请求头(可任意加).header("X-Csrf-Token", X_Csrf_Token).header("Cookie", COOKIE)//.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36").timeout(40000).execute();JSONArray rows = JSON.parseObject(execute.body()).getJSONArray("rows");System.err.println(rows.toString());List<Map<String, Object>> list = Lists.newArrayList();for (Object row : rows) {try {JSONArray jsonArray = JSON.parseArray(row.toString());String title = jsonArray.get(0).toString();Integer count = Integer.valueOf(jsonArray.get(1).toString());String content = jsonArray.get(2).toString();if (count >= maxCount) {continue;}if (filterContent.stream().anyMatch(k -> content.contains(k))) {continue;}int subContentLen = content.length() <= SUB_CONTENT_LENGTH ? content.length() : SUB_CONTENT_LENGTH;String subContent = content.substring(0, subContentLen);int subTitleLen = title.length() <= SUB_TITLE_LENGTH ? title.length() : SUB_TITLE_LENGTH;String subTitle = content.substring(0, subTitleLen);Map<String, Object> map = new HashMap<>();map.put("title", subTitle);map.put("count", count);map.put("content", subContent);list.add(map);} catch (Exception e) {log.error("{}获取日志统计数据出现异常e:{}", systemName, e);}}if (CollectionUtils.isEmpty(list)) {log.info("{}未获取到数据,请求链接url:{},token:{},cookie:{}", systemName, url, X_Csrf_Token, COOKIE);}return list;}public void sendWxMessage(String systemName, String id, List<Map<String, Object>> contentList) {if (CollectionUtils.isEmpty(contentList)) {log.error("{}发送内容为空,不发送机器人微信消息,id:{}", systemName, id);return;}String periodDesc = getPeriodDesc();final int[] topNum = {1};String StringContent = contentList.stream().map(k -> {String title = (String) k.get("title");Integer count = (Integer) k.get("count");String content = (String) k.get("content");return String.format("> top-%d:出现次数:%d\n> 错误详情描述: %s", topNum[0]++, count, content.trim());}).collect(Collectors.joining("\n\n"));String content = String.format("%s近%s内错误日志Top10\n%s", systemName, periodDesc, StringContent);String sendContent = String.format(TEMPLATE, content);//Arrays.stream(WX_ROBOT_URL.split(",")).forEach(wx -> {String post2 = HttpUtil.post(wx, sendContent);String errcode = JSON.parseObject(post2).getString("errcode");if (!"0".equals(errcode)) {log.error("{}发送微信不成功,返回数据:{}", systemName, post2);}});}private String getPeriodDesc() {if (PERIOD_HOUR <= 24) {return PERIOD_HOUR + "小时";}BigDecimal dayBigDecimal = BigDecimal.valueOf(PERIOD_HOUR).divide(BigDecimal.valueOf(24), 2, BigDecimal.ROUND_HALF_UP);String s = StrUtil.removeSuffix(StrUtil.removeSuffix(String.valueOf(dayBigDecimal), "00"), "0");String[] split = s.split("\\.");if (split.length == 1) {return split[0] + "天";}return s + "天";}/*** Jsoup 模拟登录 访问个人中心* 在登录时先输入一个错误的账号密码,查看到登录所需要的参数* 先构造登录请求参数,成功后获取到cookies* 设置request cookies,再次请求** @throws IOException*/public void jsoupLogin() throws IOException {//Jsoup加这个,避免请求https报证书问题trustEveryone();// 构造登陆参数Map<String, String> data = new HashMap<>();data.put("username", USER_NAME);data.put("password", PASSWORD);Connection.Response response = Jsoup.connect(LOG_CENTER_BASE_URL + "account/ldap/login").ignoreContentType(true) // 忽略类型验证.ignoreHttpErrors(true).followRedirects(false) // 禁止重定向.postDataCharset("utf-8").header("Upgrade-Insecure-Requests", "1").header("Accept", "application/json").header("Content-Type", "application/json").header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36").requestBody(JSON.toJSONString(data)).method(Connection.Method.POST).execute();response.charset("UTF-8");// login 中已经获取到登录成功之后的cookies// 构造访问个人中心的请求Map<String, String> cookies = response.cookies();cookies.forEach((k, v) -> COOKIE = k + "=" + v);String body = response.body();X_Csrf_Token = JSON.parseObject(body).getString("X-Csrf-Token");System.err.println("COOKIE:" + COOKIE);System.err.println("X_Csrf_Token:" + X_Csrf_Token);}public static void jsoupHandle(String id) throws IOException {String url = LOG_CENTER_BASE_URL + "jobs/" + id + "/results";Document document = Jsoup.connect(url).header("X-Csrf-Token", X_Csrf_Token).header("Cookie", COOKIE).ignoreContentType(true) // 忽略类型验证.ignoreHttpErrors(true).method(Connection.Method.GET).get();System.err.println(url);String s = JSON.toJSONString(document);System.err.println(s);}public static void trustEveryone() {try {HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {public boolean verify(String hostname, SSLSession session) {return true;}});SSLContext context = SSLContext.getInstance("TLS");context.init(null, new X509TrustManager[]{new X509TrustManager() {public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}}}, new SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());} catch (Exception e) {// e.printStackTrace();}}}

三、实现效果

企业微信机器狗开发者文档:群机器人配置说明 - 接口文档 - 企业微信开发者中心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/207223.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11月30日作业

作业&#xff1a; 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>using n…

vue.js ——Vuex

基本概念 vue进行开发过程中有没有遇到这样一种场景&#xff0c;就是有些时候一些数据是一种通用的共享数据&#xff08;比如登录信息&#xff09;&#xff0c;那么这类数据在各个组件模块中可能都会用到&#xff0c;如果每个组件中都去后台重新获取那么势必会造成性能浪费&am…

嵌入式Linux:ARM驱动+QT应用+OpenCV人脸识别项目实现

一、前言&#xff1a; 这个项目主要分为两部分&#xff0c;客户端&#xff08;ARM板端&#xff09;负责利用OpenCV采集人脸数据&#xff0c;利用TCP将人脸数据发送给服务器&#xff0c;然后服务器根据人脸数据进行人脸识别&#xff0c;将识别后的结果返还给客户端&#xff0c;客…

Unity中Shader编译目标渲染器

文章目录 前言一、Unity在打包时&#xff0c;会把Shader编译成不同平台对应的代码我们在状态栏&#xff0c;可以看见我们目前所处于的目标平台 二、在Unity中&#xff0c;怎么指定目标平台1、#pragma only_renderers2、#pragma exclude_renderers 三、我们测试一下看看效果1、 …

C语言贪吃蛇(有详细注释)

这个贪吃蛇是在比特特训营里学到的&#xff0c;同时我还写了用EasyX图形库实现的图形化贪吃蛇&#xff0c;含有每个函数的实现以及游戏中各种细节的讲解&#xff0c;感兴趣的可以去看一看。 贪吃蛇小游戏 实现效果 以下就是源码&#xff0c;感兴趣的小伙伴可以cv自己玩一玩改…

Node.js+Express+Nodemon+Socket.IO构建Web实时通信

陈拓 2023/11/23-2023/11/27 1. 简介 Websocket WebSocket是一种在单个TCP连接上提供全双工通讯的协议。特别适合需要持续数据交换的服务&#xff0c;例如在线游戏、实时交易系统等。 Websocket与Ajax之间的区别 Ajax代表异步JavaScript和XML。它被用作一组Web开发技术&…

java实战(四):编写学生信息管理系统页面·

1.要求 编写程序 实现表格的输入和编辑功能。界面如下&#xff1a; 1、用户按插入键后&#xff0c;把学号、姓名和成绩插入到最后一行&#xff0c;序号显示当前的行号。 2、当用户选中表格的某一行时&#xff0c;按删除按钮&#xff0c;则这一行从表格中删除 3、编辑功能&am…

Linux常用命令——vi命令

文章目录 vi的工作模式常用快捷键提示和技巧结论 Linux环境下的vi编辑器不仅以其强大的功能著称&#xff0c;也因其快捷键而闻名。这些快捷键可以显著提高编辑效率&#xff0c;是每个使用vi的人必须掌握的。下面将扩展介绍vi的一些常用快捷键。 vi的工作模式 vi主要有两种模式…

Linux信号超详细剖析

预备知识&#xff1a; 一、信号产生(OS发给进程) 1、键盘组合键 Linux中&#xff0c;一次登录对应一个终端&#xff0c;bash/shell。且只允许一个进程是前台进程&#xff0c;默认就是bash/shell&#xff0c;其它都是后台进程。获取键盘输入的是前台进程。 Ctrlc: 向前台进程…

【android开发-01】android中toast的用法介绍

1&#xff0c;android中toast的作用 在Android开发中&#xff0c;Toast是一种用于向用户显示简短消息的轻量级对话框。它通常用于向用户提供一些即时的反馈信息&#xff0c;例如操作结果、提示或警告。 Toast的主要作用如下&#xff1a; 提供反馈&#xff1a;Toast可以在用户…

每日一练2023.12.1——帅到没朋友【PTA】

题目链接&#xff1a;L1-020 帅到没朋友 题目要求&#xff1a; 当芸芸众生忙着在朋友圈中发照片的时候&#xff0c;总有一些人因为太帅而没有朋友。本题就要求你找出那些帅到没有朋友的人。 输入格式&#xff1a; 输入第一行给出一个正整数N&#xff08;≤100&#xff09;&…

【MySQL】视图:简化查询

文章目录 create view … as创建视图更改或删除视图drop view 删除视图replace关键字&#xff1a;更改视图 可更新视图with check option子句&#xff1a;防止行被删除视图的其他优点简化查询减小数据库设计改动的影响使用视图限制基础表访问 create view … as创建视图 把常用…

分布式锁,分布式锁应该具备哪些条件,分布式锁的实现方式有:基于Zookeeper实现、Redis实现、数据库实现

文章目录 分布式锁0-1分布式锁--包含CAP理论模型概述分布式锁&#xff1a;分布式锁应该具备哪些条件&#xff1a;分布式锁的业务场景&#xff1a; 分布式锁的实现方式有&#xff1a;基于Zookeeper - 分布式锁实现思想优缺点基于Redis - 分布式锁实现思想实现思想的具体步骤&…

Linux驱动开发——网络设备驱动(实战篇)

目录 四、 网络设备驱动实例 五、DM9000 网络设备驱动代码分析 六、NAPI 七、习题 书接上回&#xff1a; Linux驱动开发——网络设备驱动&#xff08;理论篇&#xff09;-CSDN博客 &#xff08;没看过上面博客的同学&#xff0c;skb是linux对于网络套接字缓冲区的一个虚拟…

【微服务 SpringCloudAlibaba】实用篇 · Nacos配置中心

微服务&#xff08;6&#xff09; 文章目录 微服务&#xff08;6&#xff09;1. 统一配置管理1.1 在nacos中添加配置文件1.2 从微服务拉取配置 2. 配置热更新2.1 方式一2.2 方式二 3. 配置共享1&#xff09;添加一个环境共享配置2&#xff09;在user-service中读取共享配置3&am…

vue2 el-table 封装

vue2 el-table 封装 在 custom 文件夹下面创建 tableList.vue直接上代码&#xff08;代码比较多&#xff0c;复制可直接用&#xff09; <template><div class"mp-list"><el-tableref"multipleTable"class"mp-custom-table":dat…

Ubuntu18.4中安装wkhtmltopdf + Odoo16配置【二】

deepin Linux 安装wkhtmltopdf 1、先从官网的链接里下载linux对应的包 wkhtmltopdf/wkhtmltopdf 下载需要的版本&#xff0c;推荐版本&#xff0c;新测有效&#xff1a; wkhtmltox-0.12.4_linux-generic-amd64.tar.xz 2、解压下载的文件 解压后会有一个wkhtmltox文件夹 3…

【opencv】计算机视觉基础知识

目录 前言 1、什么是计算机视觉 2、图片处理基础操作 2.1 图片处理&#xff1a;读入图像 2.2 图片处理&#xff1a;显示图像 2.3 图片处理&#xff1a;图像保存 3、图像处理入门基础 3.1 图像成像原理介绍 3.2 图像分类 3.2.1 二值图像 3.2.2灰度图像 3.2.3彩色图像…

党建引领·和谐共建——赤岗街首届微型社区养老服务公益博览会开幕

服务咨询平台&#xff0c;让社区长者更便捷地了解到养老相关政策、信息。 本次活动由赤岗街公共卫生委员会、赤岗街道办事处、中国老龄事业发展基金会老年维权基金管理委员会主办&#xff0c;珠影社区居委会、广州市穗星社会工作服务中心、广州市盈泽信息科技有限公司承办&…

4/5G互操作 EPSFB讲解

今天我们来讲一下4/5G之间之间互操作&#xff0c;以及5G的EPSFB是基于什么实现的~ 目录 4/5G互操作 重选 切换 基于覆盖的切换 基于业务的切换 两个面试问题 想要加快4G切换5G的速度&#xff0c;调哪个参数怎么调高效&#xff1f; 想要减慢5G切换4G的速度调哪个参数怎…