最近因部门需要,对 Eureka 服务上下线进行监控并发送邮件,于是便有了如下代码的产生。
application.yml
environments: dev
spring:
application:
name: eureka-server
mail:
isMailServer: true
default-encoding: UTF-8
host: mail.my00.com
username: My00ComServer
password: ******
mailFrom: Server@my00.com
port: 25
mailTo: havent@qq.com
mailCc: a@os1.cc,b@os1.cc
EurekaStateChangeListener.java
package com.d.eurekaserver;
import com.netflix.appinfo.InstanceInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRenewedEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaRegistryAvailableEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaServerStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author: havent.liu(havent@qq.com)
* @Description
* @Date 2018/10/17
*/
@Component
public class EurekaStateChangeListener {
@Autowired
private JavaMailSender mailSender;
@Value("${environments}")
private String environment;
@Value("${spring.mail.isMailServer}")
private boolean isMailServer;
@Value("${spring.mail.mailFrom}")
private String mailFrom;
@Value("${spring.mail.mailTo}")
private String mailTo;
@Value("${spring.mail.mailCc}")
private String mailCc;
private Map<String, String> serverList = new HashMap<String, String>();
@EventListener
public void listen(EurekaInstanceCanceledEvent event) {
//HH: 服务下线事件
//if (event.isReplication()) {
// return;
//}
String appName = event.getAppName();
String serverId = event.getServerId();
String serverKey = appName + "." + serverId;
String oldStatus = serverList.get(serverKey);
if (StringUtils.isBlank(oldStatus)) {
oldStatus = "";
}
if (!oldStatus.equals("OUT_OF_SERVICE")) {
serverList.put(serverKey, "OUT_OF_SERVICE");
long timeStamp = System.currentTimeMillis();
String title = "[" + appName + "] Eureka 服务下线通知";
String msg = getMessage("已下线", appName, serverId, "OUT_OF_SERVICE", timeStamp);
sendEmail(title, msg);
}
}
@EventListener
public void listen(EurekaInstanceRegisteredEvent event) {
//HH: 服务注册事件
//if (event.isReplication()) {
// return;
//}
InstanceInfo instanceInfo = event.getInstanceInfo();
if (instanceInfo == null) {
return;
}
if (instanceInfo.getStatus() != null && instanceInfo.getStatus() != InstanceInfo.InstanceStatus.UP && instanceInfo.getStatus() != InstanceInfo.InstanceStatus.STARTING) {
return;
}
String appName = instanceInfo.getAppName();
String serverId = instanceInfo.getId();
String serverKey = appName + "." + serverId;
String oldStatus = serverList.get(serverKey);
serverList.put(serverKey, "UP");
long timeStamp = System.currentTimeMillis();
if (StringUtils.isBlank(oldStatus)) {
String title = "[" + appName + "] Eureka 服务上线通知";
String msg = getMessage("已上线", appName, serverId, "UP", timeStamp);
sendEmail(title, msg);
} else if (!oldStatus.equals("UP")) {
String title = "[" + appName + "] Eureka 服务重新上线通知";
String msg = getMessage("已重新上线", appName, serverId, "UP", timeStamp);
sendEmail(title, msg);
}
}
@EventListener
public void listen(EurekaInstanceRenewedEvent event) {
//HH: 服务续约事件
//if (event.isReplication()) {
// return;
//}
InstanceInfo instanceInfo = event.getInstanceInfo();
if (instanceInfo == null) {
return;
}
InstanceInfo.InstanceStatus status = instanceInfo.getStatus();
String appName = event.getAppName();
String serverId = event.getServerId();
String serverKey = appName + "." + serverId;
String oldStatus = serverList.get(serverKey);
String currentStatus = status.toString();
if (currentStatus.equals(oldStatus)) {
return;
}
if (StringUtils.isBlank(oldStatus)) {
oldStatus = "";
}
boolean isDown = true;
if (oldStatus.equals("UP") || oldStatus.equals("STARTING")) {
isDown = false;
}
serverList.put(serverKey, status.toString());
long timeStamp = System.currentTimeMillis();
if (status == InstanceInfo.InstanceStatus.UP || status == InstanceInfo.InstanceStatus.STARTING) {
if (isDown) {
String title = "[" + appName + "] Eureka 服务恢复通知";
String msg = getMessage("已恢复", appName, serverId, status.toString(), timeStamp);
sendEmail(title, msg);
}
} else {
if (!isDown) {
String title = "[" + appName + "] Eureka 服务离线通知";
String msg = getMessage("已离线", appName, serverId, status.toString(), timeStamp);
sendEmail(title, msg);
}
}
}
@EventListener
public void listen(EurekaRegistryAvailableEvent event) {
//HH: 注册中心启动事件
SimpleDateFormat currentDate = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.S");
System.out.println(currentDate.format(System.currentTimeMillis()) + " INFO " + "注册中心启动");
//sendEmail("EurekaServer 注册中心启动", "EurekaServer 注册中心已启动");
}
@EventListener
public void listen(EurekaServerStartedEvent event) {
// HH: Server 启动事件
SimpleDateFormat currentDate = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.S");
System.out.println(currentDate.format(System.currentTimeMillis()) + " INFO " + "EurekaServer 启动");
//sendEmail("EurekaServer 服务启动", "EurekaServer Started");
}
private String getMessage(String content, String appName, String serverId, String status, long timeStamp) {
SimpleDateFormat currentDate = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.S");
String message = "微服务:" + appName + " [ " + serverId + " ] " + content + " " + status
+ "\r\n时间戳:" + currentDate.format(timeStamp) + " [" + timeStamp + "]"
+ "\r\n微环境:" + environment;
System.out.println(currentDate.format(timeStamp) + " INFO " + "微服务:" + appName + " [ " + serverId + " ] " + content + " " + status + " 微环境:" + environment);
return message;
}
// 发送邮件
@Async
protected void sendEmail(String title, String msg) {
if (!isMailServer) {
return;
}
SimpleDateFormat currentDate = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss.S");
long timeStamp = System.currentTimeMillis();
title = "[" + environment + "]" + title;
try {
// DONE: 线程沉睡5秒
//Thread.sleep(1000 * 5);
//用于封装邮件信息的实例
SimpleMailMessage smm = new SimpleMailMessage();
//邮件主题
smm.setSubject(title);
//邮件内容
smm.setText(msg);
//由谁来发送邮件
smm.setFrom(mailFrom);
//接受邮件
smm.setTo(mailTo.split(","));
if (StringUtils.isNotBlank(mailCc)) {
smm.setCc(mailCc.split(","));
}
// DONE: 开启邮件发送功能
mailSender.send(smm);
System.out.println(currentDate.format(timeStamp) + " INFO 邮件发送成功:" + msg);
} catch (Exception e) {
System.err.println(currentDate.format(timeStamp) + " ERROR 邮件发送异常:" + e.getMessage());
System.err.println(currentDate.format(timeStamp) + " ERROR 邮件发送标题: " + title);
System.out.println(currentDate.format(timeStamp) + " ERROR 邮件发送内容: \r\n" + msg);
}
}
}
因为发送邮件启用了异步功能,所以还需要在 Application.java 开启 @EnableAsync
package com.havent.eurekaserver;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}