##slack配置
spring.boot.admin: notify: slack: enabled: true ignore-changes: #empty, nothing to ignore webhook-url: https://hooks.slack.com/services/xxxxxxx channel: general username: spring cloud admin message: "*#{application.name}* (#{application.id}) is *#{to.status}*"
##调度配置
@Configuration@EnableSchedulingpublic class NotifierConfiguration { @Autowired private Notifier notifier; @Bean @Primary public RemindingNotifier remindingNotifier() { RemindingNotifier remindingNotifier = new RemindingNotifier(notifier); //时间窗口,每次报警的间隔,即这个时间窗口内不重复报警 remindingNotifier.setReminderPeriod(TimeUnit.SECONDS.toMillis(10)); return remindingNotifier; } @Scheduled(fixedRate = 5_000L) //每5秒调度一次 public void remind() { System.out.println("remind...."); remindingNotifier().sendReminders(); }}
###时间窗口 ~/.m2/repository/de/codecentric/spring-boot-admin-server/1.4.6/spring-boot-admin-server-1.4.6-sources.jar!/de/codecentric/boot/admin/notify/RemindingNotifier.java
public void sendReminders() { long now = System.currentTimeMillis(); for (Reminder reminder : new ArrayList<>(reminders.values())) { if (now - reminder.getLastNotification() > reminderPeriod) { reminder.setLastNotification(now); delegate.notify(reminder.getEvent()); } } }
###是否该报警的判断
private String[] reminderStatuses = { "DOWN", "OFFLINE" }; @Override public void doNotify(ClientApplicationEvent event) { delegate.notify(event); if (shouldEndReminder(event)) { reminders.remove(event.getApplication().getId()); } else if (shouldStartReminder(event)) { reminders.putIfAbsent(event.getApplication().getId(), new Reminder(event)); } } public void sendReminders() { long now = System.currentTimeMillis(); for (Reminder reminder : new ArrayList<>(reminders.values())) { if (now - reminder.getLastNotification() > reminderPeriod) { reminder.setLastNotification(now); delegate.notify(reminder.getEvent()); } } } protected boolean shouldStartReminder(ClientApplicationEvent event) { if (event instanceof ClientApplicationStatusChangedEvent) { return Arrays.binarySearch(reminderStatuses, event.getApplication().getStatusInfo().getStatus()) >= 0; } return false; } protected boolean shouldEndReminder(ClientApplicationEvent event) { if (event instanceof ClientApplicationDeregisteredEvent) { return true; } if (event instanceof ClientApplicationStatusChangedEvent) { return Arrays.binarySearch(reminderStatuses, event.getApplication().getStatusInfo().getStatus()) < 0; } return false; }
状态在{"DOWN", "OFFLINE"}的,就加入到reminders中,不在的话,从reminders中移除。 在调度期间,如果status变为up了,会先报警,然后再判断是否应该删除该事件。
###notifier
delegate.notify(event); 这里的delegate为SlackNotifier
public class SlackNotifier extends AbstractStatusChangeNotifier { //...}
继承了AbstractStatusChangeNotifier
public abstract class AbstractStatusChangeNotifier extends AbstractEventNotifier { /** * List of changes to ignore. Must be in Format OLD:NEW, for any status use * as wildcard, e.g. * *:UP or OFFLINE:* */ private String[] ignoreChanges = { "UNKNOWN:UP" }; @Override protected boolean shouldNotify(ClientApplicationEvent event) { if (event instanceof ClientApplicationStatusChangedEvent) { ClientApplicationStatusChangedEvent statusChange = (ClientApplicationStatusChangedEvent) event; String from = statusChange.getFrom().getStatus(); String to = statusChange.getTo().getStatus(); return Arrays.binarySearch(ignoreChanges, from + ":" + to) < 0 && Arrays.binarySearch(ignoreChanges, "*:" + to) < 0 && Arrays.binarySearch(ignoreChanges, from + ":*") < 0; } return false; } public void setIgnoreChanges(String[] ignoreChanges) { String[] copy = Arrays.copyOf(ignoreChanges, ignoreChanges.length); Arrays.sort(copy); this.ignoreChanges = copy; }}
这里对ignore的逻辑进行了判断,不满足条件的不会调用doNotify
public void notify(ClientApplicationEvent event) { if (enabled && shouldNotify(event)) { try { doNotify(event); } catch (Exception ex) { getLogger().error("Couldn't notify for event {} ", event, ex); } } }
doNotify才是真正的发送slack
@Override protected void doNotify(ClientApplicationEvent event) throws Exception { restTemplate.postForEntity(webhookUrl, createMessage(event), Void.class); }
实例
##doc