diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/DingTalkTextMsg.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/DingTalkTextMsg.java index b548bad87f..4a77d9b7cc 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/DingTalkTextMsg.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/DingTalkTextMsg.java @@ -1,25 +1,32 @@ package com.epmet.commons.tools.dto.form; import com.alibaba.fastjson.JSON; -import lombok.Data; import org.springframework.util.CollectionUtils; +import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; -/** - * desc: 钉钉文本消息参数 实体类 - * date: 2019/2/20 11:00 +/** + * desc: 钉钉文本消息参数 实体类 + * + * @date: 2020/6/29 9:06 * @author: jianjun liu - * email:liujianjun@yunzongnet.com + * email:liujianjun@git.elinkit.com.cn */ -public class DingTalkTextMsg { +public class DingTalkTextMsg implements Serializable { + private static final long serialVersionUID = -3611771312188821915L; /** * 消息接收者 */ - private String receiver; + private String webHook; + + /** + * 密钥 + */ + private String secret; /** * 发送内容 */ @@ -35,12 +42,12 @@ public class DingTalkTextMsg { */ private boolean isAtAll; - public String getReceiver() { - return receiver; + public String getWebHook() { + return webHook; } - public void setReceiver(String receiver) { - this.receiver = receiver; + public void setWebHook(String webHook) { + this.webHook = webHook; } public String getContent() { @@ -67,6 +74,14 @@ public class DingTalkTextMsg { isAtAll = atAll; } + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + public String getMsgContent() { Map items = new HashMap<>(); items.put("msgtype", "text"); diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/filter/LogMsgSendFilter.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/filter/LogMsgSendFilter.java index 826bb05905..4f24fa70d2 100644 --- a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/filter/LogMsgSendFilter.java +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/filter/LogMsgSendFilter.java @@ -6,8 +6,9 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.StackTraceElementProxy; import ch.qos.logback.core.spi.FilterReply; -import com.epmet.commons.tools.utils.HttpClientManager; -import com.epmet.commons.tools.utils.Result; +import com.epmet.commons.tools.dto.form.DingTalkTextMsg; +import com.epmet.commons.tools.utils.DingdingMsgSender; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,78 +21,96 @@ import java.text.SimpleDateFormat; * @author: jianjun liu */ public class LogMsgSendFilter extends LevelFilter { - private static final Logger logger = LoggerFactory.getLogger(LogMsgSendFilter.class); - @Override - public FilterReply decide(ILoggingEvent event) { - //如果日志级别等于设置的日志级别 则发送消息 - if (event.getLevel().isGreaterOrEqual(Level.ERROR)) { - try { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("【日志告警】\n"); + private static final Logger logger = LoggerFactory.getLogger(LogMsgSendFilter.class); + private DingdingMsgSender msgSender = new DingdingMsgSender(); + private String webHook; + private String secret; - stringBuilder.append("\n"); + @Override + public FilterReply decide(ILoggingEvent event) { + //如果日志级别等于设置的日志级别 则发送消息 + if (event.getLevel().isGreaterOrEqual(Level.ERROR)) { + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("【日志告警】\n"); - stringBuilder.append("告警级别:" + event.getLevel()); - stringBuilder.append("\n"); - stringBuilder.append("故障时间:" + formatLongTime2Str(event.getTimeStamp())); - stringBuilder.append("\n"); - stringBuilder.append("TraceId:" + Thread.currentThread().getName()); - stringBuilder.append("\n"); - stringBuilder.append("告警信息:" + event.getFormattedMessage()); - stringBuilder.append("\n"); + stringBuilder.append("\n"); - IThrowableProxy throwableProxy = event.getThrowableProxy(); - //异常信息处理 暂时处理一级的5行数据 - apendStackInfo(stringBuilder, throwableProxy); + stringBuilder.append("告警级别:" + event.getLevel()); + stringBuilder.append("\n"); + stringBuilder.append("故障时间:" + formatLongTime2Str(event.getTimeStamp())); + stringBuilder.append("\n"); + stringBuilder.append("TraceId:" + Thread.currentThread().getName()); + stringBuilder.append("\n"); + stringBuilder.append("告警信息:" + event.getFormattedMessage()); + stringBuilder.append("\n"); - Result flag = HttpClientManager.getInstance().sendAlarmMsg(stringBuilder.toString()); - if (!flag.success()) { - logger.warn("msgSender.sendMsg fail,param:{}", stringBuilder.toString()); - } - } catch (Exception e) { - logger.warn("decide exception", e); - } - } - //交给其他filter继续向下处理 - return super.decide(event); - } + IThrowableProxy throwableProxy = event.getThrowableProxy(); + //异常信息处理 暂时处理一级的5行数据 + apendStackInfo(stringBuilder, throwableProxy); + DingTalkTextMsg msg = new DingTalkTextMsg(); + msg.setContent(stringBuilder.toString()); + if (StringUtils.isNotBlank(webHook)) { + msg.setWebHook(webHook); + } + if (StringUtils.isNotBlank(secret)) { + msg.setSecret(secret); + } + boolean flag = msgSender.sendMsgAsync(msg); + if (!flag) { + logger.warn("msgSender.sendMsg fail,param:{}", stringBuilder.toString()); + } + } catch (Exception e) { + logger.warn("decide exception", e); + } + } + //交给其他filter继续向下处理 + return super.decide(event); + } - private void apendStackInfo(StringBuilder stringBuilder, IThrowableProxy throwableProxy) { - int defaultRowLine = 5; - if (throwableProxy != null) { - stringBuilder.append("异常信息:") - .append(throwableProxy.getClassName()) - .append(" : ") - .append(throwableProxy.getMessage()) - .append("\n"); + private void apendStackInfo(StringBuilder stringBuilder, IThrowableProxy throwableProxy) { + int defaultRowLine = 5; + if (throwableProxy != null) { + stringBuilder.append("异常信息:") + .append(throwableProxy.getClassName()) + .append(" : ") + .append(throwableProxy.getMessage()) + .append("\n"); - StackTraceElementProxy[] stackTraceElementProxyArray = throwableProxy.getStackTraceElementProxyArray(); - StackTraceElementProxy stackTraceElementProxy = null; + StackTraceElementProxy[] stackTraceElementProxyArray = throwableProxy.getStackTraceElementProxyArray(); + StackTraceElementProxy stackTraceElementProxy = null; - if (stackTraceElementProxyArray.length < defaultRowLine) { - defaultRowLine = stackTraceElementProxyArray.length; - } - for (int i = 0; i < defaultRowLine; i++) { - stackTraceElementProxy = stackTraceElementProxyArray[i]; - StackTraceElement stackTraceElement = stackTraceElementProxy.getStackTraceElement(); - stringBuilder.append("\t\tat "); - stringBuilder.append(stackTraceElement.getClassName()); - stringBuilder.append("."); - stringBuilder.append(stackTraceElement.getMethodName()); - stringBuilder.append("("); - stringBuilder.append(stackTraceElement.getFileName()); - stringBuilder.append(":"); - stringBuilder.append(stackTraceElement.getLineNumber()); - stringBuilder.append(")"); - stringBuilder.append("\n"); - } - } - } + if (stackTraceElementProxyArray.length < defaultRowLine) { + defaultRowLine = stackTraceElementProxyArray.length; + } + for (int i = 0; i < defaultRowLine; i++) { + stackTraceElementProxy = stackTraceElementProxyArray[i]; + StackTraceElement stackTraceElement = stackTraceElementProxy.getStackTraceElement(); + stringBuilder.append("\t\tat "); + stringBuilder.append(stackTraceElement.getClassName()); + stringBuilder.append("."); + stringBuilder.append(stackTraceElement.getMethodName()); + stringBuilder.append("("); + stringBuilder.append(stackTraceElement.getFileName()); + stringBuilder.append(":"); + stringBuilder.append(stackTraceElement.getLineNumber()); + stringBuilder.append(")"); + stringBuilder.append("\n"); + } + } + } - private String formatLongTime2Str(long timestamp) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - return dateFormat.format(timestamp); - } + private String formatLongTime2Str(long timestamp) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + return dateFormat.format(timestamp); + } + public void setWebHook(String webHook) { + this.webHook = webHook; + } + + public void setSecret(String secret) { + this.secret = secret; + } } diff --git a/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/DingdingMsgSender.java b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/DingdingMsgSender.java new file mode 100644 index 0000000000..40420d1be7 --- /dev/null +++ b/epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/utils/DingdingMsgSender.java @@ -0,0 +1,185 @@ +package com.epmet.commons.tools.utils; + +import com.alibaba.fastjson.JSON; +import com.epmet.commons.tools.dto.form.DingTalkTextMsg; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.Lists; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.PreDestroy; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * desc: 发送消息工具类 + * + * @date: 2020/6/29 8:43 + * @author: jianjun liu + */ +@Component +public class DingdingMsgSender { + + private final Logger logger = LoggerFactory.getLogger(DingdingMsgSender.class); + //如果不设置则为 开发环境机器人地址 + private static final String webHook = "https://oapi.dingtalk.com/robot/send?access_token=90782b119f82a5b6bb8e0f819b6a77bbc2102b53aa2d7d2e24fa10b66d580b1c"; + private static final String secret = "SEC080aac67ff78e79fdaba132aa51e3fb3f6060dec99492feaac82cabf9f8b6a19"; + /** + * 默认10 + */ + private static Integer maxQueueSize = 10; + + /** + * 有序队列 + */ + private ArrayBlockingQueue msgQueue = new ArrayBlockingQueue<>(maxQueueSize); + + + private volatile boolean running = false; + + private Cache limitCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(1000).build(); + + public DingdingMsgSender() { + + } + + + private void handleMsg() { + DingTalkTextMsg msg = null; + try { + //阻塞取元素 + msg = msgQueue.take(); + if (msg != null) { + AtomicInteger limitCount = limitCache.getIfPresent(msg.getWebHook()); + if (limitCount == null) { + limitCount = new AtomicInteger(1); + limitCache.put(msg.getWebHook(), limitCount); + } + if (limitCount.intValue() > maxQueueSize) { + msgQueue.offer(msg); + Thread.sleep(1000); + } else { + sendPostByJSON(msg); + limitCount.addAndGet(1); + } + } else { + Thread.sleep(1000); + } + } catch (Exception e) { + logger.warn("handleMsg exception,serverUrl:" + msg.getWebHook() + ",msg:" + JSON.toJSONString(msg), e); + } + } + + + /** + * desc:异步发送消息 + * + * @param messageParam + * @return + * @throws IOException + */ + public boolean sendMsgAsync(DingTalkTextMsg messageParam) { + if (!running) { + running = true; + getThread().start(); + } + boolean flag = false; + int currentQueueSize = msgQueue.size(); + //非阻塞 添加/删除元素 + if (currentQueueSize < maxQueueSize) { + flag = msgQueue.offer(messageParam); + } else { + msgQueue.poll(); + + DingTalkTextMsg param = new DingTalkTextMsg(); + param.setContent("待发送消息队列已满,当前队列个数" + msgQueue.size() + "\n" + "最新消息内容:" + JSON.toJSONString(messageParam)); + param.setWebHook(messageParam.getWebHook()); + sendPostByJSON(param); + } + return flag; + } + + /** + * 同步发送报警 + * + * @param messageParam + * @return + * @throws IOException + */ + public Result sendMsgSync(DingTalkTextMsg messageParam) { + return sendPostByJSON(messageParam); + } + + private Thread getThread() { + Thread sendMsgThread = new Thread("MsgSender-Thread") { + @Override + public void run() { + while (running) { + handleMsg(); + } + } + }; + return sendMsgThread; + } + + + @PreDestroy + public void destroy() { + running = false; + } + + /** + * 发送POST 请求 + * + * @param param 请求参数,JSON格式 + * @return + */ + private Result sendPostByJSON(DingTalkTextMsg param) { + if (StringUtils.isBlank(param.getWebHook())) { + param.setWebHook(webHook); + } + if (StringUtils.isBlank(param.getSecret())) { + param.setSecret(secret); + } + Result result = new Result().error(); + Long timestamp = System.currentTimeMillis(); + try { + String stringToSign = timestamp + "\n" + param.getSecret(); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(param.getSecret().getBytes("UTF-8"), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); + String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); + String url = param.getWebHook(); + url = url.concat("×tamp=" + timestamp + "&sign=" + sign); + String jsonStrParam = param.getMsgContent(); + result = HttpClientManager.getInstance().sendPostByJSON(url, jsonStrParam); + } catch (Exception e) { + logger.warn("sendPostByJSON error", e); + } + return result; + } + + + public static void main(String[] args) { + for (int i = 0; i < 50; i++) { + + DingTalkTextMsg dingTalkTextMsg = new DingTalkTextMsg(); + dingTalkTextMsg.setWebHook(""); + dingTalkTextMsg.setContent("测试消息" + i); + dingTalkTextMsg.setAtMobiles(Lists.newArrayList()); + dingTalkTextMsg.setAtAll(false); + dingTalkTextMsg.setSecret(""); + DingdingMsgSender msgSender = new DingdingMsgSender(); + msgSender.sendMsgAsync(dingTalkTextMsg); + } + } +} diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/DemoController.java b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/DemoController.java index 2f6e7ac226..5f562630dc 100644 --- a/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/DemoController.java +++ b/epmet-module/data-statistical/data-statistical-server/src/main/java/com/epmet/controller/DemoController.java @@ -2,20 +2,21 @@ package com.epmet.controller; import com.epmet.dto.AgencySubTreeDto; import com.epmet.service.StatsDemoService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; +import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.List; - @RequestMapping("demo") @RestController +@Slf4j public class DemoController { @Autowired @@ -24,6 +25,13 @@ public class DemoController { @Autowired private ExecutorService executorService; + @GetMapping("testAlarm") + public void testAlarm() { + for (int i = 0; i < 20; i++) { + log.error("测试消息"+i); + } + } + @GetMapping("testtx") public void testTx() { demoService.testTx(); diff --git a/epmet-module/data-statistical/data-statistical-server/src/main/resources/logback-spring.xml b/epmet-module/data-statistical/data-statistical-server/src/main/resources/logback-spring.xml index 148588bffb..fb3deaefb1 100644 --- a/epmet-module/data-statistical/data-statistical-server/src/main/resources/logback-spring.xml +++ b/epmet-module/data-statistical/data-statistical-server/src/main/resources/logback-spring.xml @@ -130,6 +130,8 @@ ERROR ACCEPT DENY + https://oapi.dingtalk.com/robot/send?access_token=90782b119f82a5b6bb8e0f819b6a77bbc2102b53aa2d7d2e24fa10b66d580b1c + SEC080aac67ff78e79fdaba132aa51e3fb3f6060dec99492feaac82cabf9f8b6a19