diff --git a/hippo4j-example/hippo4j-spring-boot-starter-example/src/main/resources/application.properties b/hippo4j-example/hippo4j-spring-boot-starter-example/src/main/resources/application.properties index 3d283f86..8d3ade56 100644 --- a/hippo4j-example/hippo4j-spring-boot-starter-example/src/main/resources/application.properties +++ b/hippo4j-example/hippo4j-spring-boot-starter-example/src/main/resources/application.properties @@ -24,3 +24,20 @@ spring.dynamic.thread-pool.monitor.collect-types=server,micrometer spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic,web spring.dynamic.thread-pool.monitor.initial-delay=10000 spring.dynamic.thread-pool.monitor.collect-interval=5000 + +# for email notify +## simple example +spring.mail.host=smtp.qq.com +spring.mail.username=xxx@qq.com +spring.mail.password=xxx + +## for gmail need ssl +#spring.mail.host=smtp.gmail.com +#spring.mail.username=xxx@gmail.com +#spring.mail.password=xxx +#spring.mail.protocol=smtp +#spring.mail.properties.mail.smtp.auth=true +#spring.mail.properties.mail.smtp.port=465 +#spring.mail.properties.mail.smtp.starttls.enable=true +#spring.mail.properties.mail.smtp.starttls.required=true +#spring.mail.properties.mail.smtp.ssl.enable=true diff --git a/hippo4j-message/pom.xml b/hippo4j-message/pom.xml index 3a2b349d..02de5617 100644 --- a/hippo4j-message/pom.xml +++ b/hippo4j-message/pom.xml @@ -24,6 +24,14 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-mail + + + org.freemarker + freemarker + @@ -33,6 +41,7 @@ **/*.txt **/*.json + **/*.ftl diff --git a/hippo4j-message/src/main/java/cn/hippo4j/message/config/MessageConfiguration.java b/hippo4j-message/src/main/java/cn/hippo4j/message/config/MessageConfiguration.java index e495cfe4..63899819 100644 --- a/hippo4j-message/src/main/java/cn/hippo4j/message/config/MessageConfiguration.java +++ b/hippo4j-message/src/main/java/cn/hippo4j/message/config/MessageConfiguration.java @@ -19,6 +19,7 @@ package cn.hippo4j.message.config; import cn.hippo4j.message.api.NotifyConfigBuilder; import cn.hippo4j.message.platform.DingSendMessageHandler; +import cn.hippo4j.message.platform.EmailSendMessageHandler; import cn.hippo4j.message.platform.LarkSendMessageHandler; import cn.hippo4j.message.platform.WeChatSendMessageHandler; import cn.hippo4j.message.service.AlarmControlHandler; @@ -57,4 +58,9 @@ public class MessageConfiguration { public SendMessageHandler weChatSendMessageHandler() { return new WeChatSendMessageHandler(); } + + @Bean + public EmailSendMessageHandler emailSendMessageHandler() { + return new EmailSendMessageHandler(); + } } diff --git a/hippo4j-message/src/main/java/cn/hippo4j/message/enums/NotifyPlatformEnum.java b/hippo4j-message/src/main/java/cn/hippo4j/message/enums/NotifyPlatformEnum.java index 5ffbad3b..0d5aa7c3 100644 --- a/hippo4j-message/src/main/java/cn/hippo4j/message/enums/NotifyPlatformEnum.java +++ b/hippo4j-message/src/main/java/cn/hippo4j/message/enums/NotifyPlatformEnum.java @@ -35,5 +35,10 @@ public enum NotifyPlatformEnum { /** * WECHAT */ - WECHAT + WECHAT, + + /** + * EMAIL + */ + EMAIL } diff --git a/hippo4j-message/src/main/java/cn/hippo4j/message/platform/EmailSendMessageHandler.java b/hippo4j-message/src/main/java/cn/hippo4j/message/platform/EmailSendMessageHandler.java new file mode 100644 index 00000000..9edd3646 --- /dev/null +++ b/hippo4j-message/src/main/java/cn/hippo4j/message/platform/EmailSendMessageHandler.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.message.platform; + +import cn.hippo4j.common.toolkit.FileUtil; +import cn.hippo4j.common.toolkit.Singleton; +import cn.hippo4j.message.dto.NotifyConfigDTO; +import cn.hippo4j.message.enums.NotifyPlatformEnum; +import cn.hippo4j.message.platform.constant.EmailAlarmConstants; +import cn.hippo4j.message.request.AlarmNotifyRequest; +import cn.hippo4j.message.request.ChangeParameterNotifyRequest; +import cn.hippo4j.message.service.SendMessageHandler; +import freemarker.cache.StringTemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Template; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.boot.autoconfigure.mail.MailProperties; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; + +import javax.annotation.Resource; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import java.io.StringWriter; +import java.io.Writer; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +/** + * Send Email notification message. + */ +@Slf4j +public class EmailSendMessageHandler implements SendMessageHandler { + + @Resource + private JavaMailSender emailSender; + + @Resource + MailProperties mailProperties; + + @Override + public String getType() { + return NotifyPlatformEnum.EMAIL.name(); + } + + @Override + public void sendAlarmMessage(NotifyConfigDTO notifyConfig, AlarmNotifyRequest alarmNotifyRequest) { + try { + String emailAlarmTxtKey = "message/robot/dynamic-thread-pool/email-alarm.ftl"; + Map dataModel = getDataModel(alarmNotifyRequest); + dataModel.put("interval", notifyConfig.getInterval().toString()); + String emailAlarmTxt = Singleton.get(emailAlarmTxtKey, () -> FileUtil.readUtf8String(emailAlarmTxtKey)); + String renderedEmailAlarmTxt = render(dataModel, emailAlarmTxt); + String alarmSubject = render(dataModel, EmailAlarmConstants.Email_ALARM_TITLE); + String[] recipients = notifyConfig.getReceives().split(","); + execute(recipients, alarmSubject, renderedEmailAlarmTxt); + } catch (Exception e) { + log.error("Email failed to send message", e); + } + } + + @Override + public void sendChangeMessage(NotifyConfigDTO notifyConfig, ChangeParameterNotifyRequest changeParameterNotifyRequest) { + try { + String emailConfigTxtKey = "message/robot/dynamic-thread-pool/email-config.ftl"; + Map dataModel = getDataModel(changeParameterNotifyRequest); + String emailConfigTxt = Singleton.get(emailConfigTxtKey, () -> FileUtil.readUtf8String(emailConfigTxtKey)); + String renderedEmailConfigTxt = render(dataModel, emailConfigTxt); + String configSubject = render(dataModel, EmailAlarmConstants.Email_NOTICE_TITLE); + String[] recipients = notifyConfig.getReceives().split(","); + execute(recipients, configSubject, renderedEmailConfigTxt); + } catch (Exception e) { + log.error("Email failed to send message", e); + } + } + + private String render(Map dataModel, String stringTemplate) { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); + StringTemplateLoader stringLoader = new StringTemplateLoader(); + stringLoader.putTemplate("renderTemplate", stringTemplate); + cfg.setTemplateLoader(stringLoader); + Writer out = new StringWriter(2048); + try { + Template tpl = cfg.getTemplate("renderTemplate", "UTF-8"); + tpl.process(dataModel, out); + } catch (Exception e) { + log.error("failed to render template,dataModel:{},stringTemplate:{}", dataModel, stringTemplate); + } + return out.toString(); + } + + @SneakyThrows + private Map getDataModel(Object bean) { + Map dataModel = BeanUtils.describe(bean); + dataModel.put("from", mailProperties.getUsername()); + dataModel.put("date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + return dataModel; + } + + private void execute(String[] to, String subject, String htmlBody) throws MessagingException { + MimeMessage message = emailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, "UTF-8"); + helper.setFrom(mailProperties.getUsername()); + helper.setTo(to); + helper.setSubject(subject); + helper.setText(htmlBody, true); + emailSender.send(message); + } +} \ No newline at end of file diff --git a/hippo4j-message/src/main/java/cn/hippo4j/message/platform/constant/EmailAlarmConstants.java b/hippo4j-message/src/main/java/cn/hippo4j/message/platform/constant/EmailAlarmConstants.java new file mode 100644 index 00000000..b20c45dc --- /dev/null +++ b/hippo4j-message/src/main/java/cn/hippo4j/message/platform/constant/EmailAlarmConstants.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.message.platform.constant; + +/** + * Email alarm constants. + */ +public class EmailAlarmConstants { + + /** + * Thread Pool Alert Notification Title + */ + public static String Email_ALARM_TITLE = "【Hippo4J】${active}-${threadPoolId} 线程池 ${notifyTypeEnum} 预警"; + + /** + * Thread pool parameter change notification title + */ + public static String Email_NOTICE_TITLE = "【Hippo4J】${active}-${threadPoolId} 线程池参数变更通知"; +} \ No newline at end of file diff --git a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-alarm.ftl b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-alarm.ftl new file mode 100644 index 00000000..ef1fd737 --- /dev/null +++ b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-alarm.ftl @@ -0,0 +1,28 @@ +[警报] ${active} - 动态线程池运行告警(${notifyTypeEnum}) +
    +
  • 线程池ID:${threadPoolId}
  • +
  • 应用名称:${appName}
  • +
  • 应用实例:${identify}
  • +
  • 核心线程数:${corePoolSize}
  • +
  • 最大线程数:${maximumPoolSize}
  • +
  • 当前线程数:${poolSize}
  • +
  • 活跃线程数:${activeCount}
  • +
  • 同存最大线程数:${largestPoolSize}
  • +
  • 线程池任务总量:${completedTaskCount}
  • +
  • 队列类型:${queueName}
  • +
  • 队列容量:${capacity}
  • +
  • 队列元素个数:${queueSize}
  • +
  • 队列剩余个数:${remainingCapacity}
  • +
  • 拒绝策略:${rejectedExecutionHandlerName}
  • +
  • 拒绝策略执行次数:${rejectCountNum}
  • +
  • OWNER:${from}
  • +
  • 提示:${interval} 分钟内此线程池不会重复告警(可配置)
  • +
+ + 播报时间:${date} + + \ No newline at end of file diff --git a/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-config.ftl b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-config.ftl new file mode 100644 index 00000000..620b3305 --- /dev/null +++ b/hippo4j-message/src/main/resources/message/robot/dynamic-thread-pool/email-config.ftl @@ -0,0 +1,24 @@ +[通知] ${active} - 动态线程池参数变更 +
    +
  • 线程池ID:${threadPoolId}
  • +
  • 应用名称:${appName}
  • +
  • 应用实例:${identify}
  • +
  • 核心线程数:${beforeCorePoolSize} -> ${nowCorePoolSize}
  • +
  • 核心线程超时:${beforeMaximumPoolSize} -> ${nowMaximumPoolSize}
  • +
  • 线程存活时间:${beforeAllowsCoreThreadTimeOut} -> ${nowAllowsCoreThreadTimeOut}
  • +
  • 执行超时时间:${beforeKeepAliveTime} -> ${nowKeepAliveTime}
  • +
  • 队列类型:${blockingQueueName}
  • +
  • 队列容量:${beforeQueueCapacity} -> ${nowQueueCapacity}
  • +
  • AGO 拒绝策略:${beforeRejectedName}
  • +
  • NOW 拒绝策略:${nowRejectedName}
  • +
  • OWNER: ${from}
  • +
  • 提示:动态线程池配置变更实时通知(无限制)
  • +
+ + 播报时间:${date} + + diff --git a/pom.xml b/pom.xml index f19c94e8..3bc533f3 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,7 @@ 3.0 2.22.1 3.1.0 + 2.3.31 @@ -126,6 +127,11 @@ netty-all ${netty.version} + + org.freemarker + freemarker + ${freemarker.version} +