All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taotao.boot.monitor.warn.WarnProvider Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2020-2030, Shuigedeng ([email protected] & https://blog.taotaocloud.top/).
 *
 * Licensed 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
 *
 *      https://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 com.taotao.boot.monitor.warn;

import com.taotao.boot.common.constant.CommonConstant;
import com.taotao.boot.common.constant.StarterName;
import com.taotao.boot.common.utils.common.PropertyUtils;
import com.taotao.boot.common.utils.lang.StringUtils;
import com.taotao.boot.common.utils.log.LogUtils;
import com.taotao.boot.common.utils.servlet.RequestUtils;
import com.taotao.boot.monitor.Monitor;
import com.taotao.boot.monitor.enums.WarnTypeEnum;
import com.taotao.boot.monitor.model.Message;
import com.taotao.boot.monitor.properties.WarnProperties;
import com.taotao.boot.monitor.utils.ExceptionUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WarnProvider
 *
 * @author shuigedeng
 * @version 2021.9
 * @since 2021-09-09 11:04:53
 */
public class WarnProvider extends AbstractWarn implements AutoCloseable, ApplicationRunner {

    private boolean isClose;
    private final Monitor monitorThreadPool;
    private final WarnProperties warnProperties;
    private final DuplicateFilter duplicateFilter;
    private final Object lock = new Object();
    private final List warns = new ArrayList<>();
    private final ConcurrentLinkedDeque messages = new ConcurrentLinkedDeque<>();
    private final AtomicInteger atomicInteger = new AtomicInteger(0);
    private final AtomicBoolean atomicChannel = new AtomicBoolean(false);

    public WarnProvider(WarnProperties warnProperties, Monitor monitorThreadPool) {
        this.warnProperties = warnProperties;
        this.monitorThreadPool = monitorThreadPool;
        this.duplicateFilter = new DuplicateFilter(warnProperties);
        this.isClose = false;

        registerWarn();

        this.monitorThreadPool.monitorSubmit("系统任务: WarnProvider 实时报警任务", () -> {
            while (!this.monitorThreadPool.monitorIsShutdown() && !isClose) {
                try {
                    notifyRunning();
                } catch (Exception exp) {
                    LogUtils.warn(StarterName.MONITOR_STARTER, "WarnProvider 消息循环异常");
                }

                try {
                    Thread.sleep(warnProperties.getTimeSpan() * 1000L);
                } catch (Exception e) {
                    LogUtils.error(e);
                }
            }
        });
    }

    /**
     * registerWarn
     *
     *
     * @since 2021-09-10 16:18:47
     */
    public void registerWarn() {
        if (warnProperties.isDingDingWarnEnabled()) {
            warns.add(new DingdingWarn());
        }

        if (warnProperties.getEmailWarnEnabled()) {
            warns.add(new MailWarn());
        }

        if (warnProperties.getSmsWarnEnabled()) {
            warns.add(new SmsWarn());
        }

        warns.add(new LoggerWarn());
    }

    /**
     * clearWarn
     *
     *
     * @since 2021-09-10 16:19:01
     */
    public void clearWarn() {
        warns.clear();
    }

    /**
     * notifyRunning
     *
     *
     * @since 2021-09-10 16:19:04
     */
	private void notifyRunning() {
		Message msg = new Message();
		msg.setWarnType(WarnTypeEnum.WARN);

		List msgs = getAllMessage();
		int msgCount = atomicInteger.getAndSet(0);
		if (msgCount > 0) {
			StringBuilder content = new StringBuilder();
			content.append(
				String.format("最新报警累计:%s条,详情请查看日志系统,最后%s条报警内容如下:\n", msgCount, warnProperties.getCacheCount()));

			msgs.forEach(c -> {
				if (c.getWarnType().getLevel() > (msg.getWarnType()).getLevel()) {
					msg.setWarnType(c.getWarnType());
				}
				content.append(String.format(
					"[%s][%s]内容%s\n", c.getWarnType().getDescription(), c.getTitle(), c.getContent()));
			});

			msg.setTitle(String.format("收到%s条报警", msgCount));
			msg.setContent(content.toString());
			notifyNow(msg);
		}
	}

    @Override
    public void notify(Message message) {
        addMessage(message);
    }

    /**
     * notify
     *
     * @param warnType warnType
     * @param title title
     * @param content content
     *
     * @since 2021-09-10 16:19:41
     */
    public void notify(String warnType, String title, String content) {
        Message message = new Message(WarnTypeEnum.valueOf(warnType), title, content);
        addMessage(message);
    }

    /**
     * addMessage
     *
     * @param msg msg
     *
     * @since 2021-09-10 16:19:44
     */
    private void addMessage(Message msg) {
        atomicInteger.getAndIncrement();

        // 加锁
        synchronized (lock) {
            messages.add(msg);

            // 清理多余
            if (messages.size() > warnProperties.getCacheCount()) {
                int cacheCount = warnProperties.getCacheCount();
                for (int i = 0; i < messages.size() - cacheCount; i++) {
                    if (!messages.isEmpty()) {
                        messages.removeFirst();
                    }
                }
            }
        }
    }

    /**
     * getAllMessage
     *
     * @return {@link List }
     *
     * @since 2021-09-10 16:20:17
     */
    private List getAllMessage() {
        List msgs = new ArrayList<>(messages.size());
        synchronized (lock) {
            msgs.addAll(messages);
            messages.clear();
        }
        return msgs;
    }

    /**
     * notifyNow
     *
     * @param message message
     *
     * @since 2021-09-10 16:20:33
     */
    public void notifyNow(Message message) {
        notifyMessage0(message);
    }

    /**
     * notifyNow
     *
     * @param warnType warnType
     * @param title title
     * @param content content
     *
     * @since 2021-09-10 16:20:38
     */
    public void notifyNow(String warnType, String title, String content) {
        Message message = new Message(WarnTypeEnum.valueOf(warnType), title, content);
        notifyMessage0(message);
    }

    /**
     * 方法私有化,避免重载方法循环调用
     *
     * @param message message
     *
     * @since 2021-09-10 16:20:48
     */
    private void notifyMessage0(Message message) {
        if (!duplicateFilter.ifDuplicate(message.getContent()) && atomicChannel.get()) {
            if (WarnTypeEnum.ERROR == message.getWarnType()) {
                ExceptionUtils.reportException(message);
            }

            for (AbstractWarn warn : warns) {
                message.setTitle(String.format(
                        "[%s][%s][%s][%s]%s",
                        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),
                        RequestUtils.getIpAddress(),
                        PropertyUtils.getProperty(CommonConstant.SPRING_APP_NAME_KEY),
                        PropertyUtils.getProperty(CommonConstant.SPRING_APP_NAME_KEY),
                        StringUtils.nullToEmpty(message.getTitle())));
                warn.notify(message);
            }
        }
    }

    @Override
    public void close() {
        isClose = true;
    }

    @Override
    public void run(ApplicationArguments args) {
        atomicChannel.getAndSet(true);
        LogUtils.info(StarterName.MONITOR_STARTER, "开启消息通道");
    }

    /**
     * 简单重复过滤算法 去除数值并hash
     *
     *
     * @version 2021.9
     * @since 2021-09-10 16:21:09
     */
    private static class DuplicateFilter {

        private WarnProperties warnProperties;
        private int cacheMax = 100;
        private volatile List cacheTag = new ArrayList<>(cacheMax + 5);
        private long lastClearTime = System.currentTimeMillis();

        public DuplicateFilter(WarnProperties warnProperties) {
            this.warnProperties = warnProperties;
        }

        /**
         * ifDuplicate
         *
         * @param message message
         * @return boolean
         *
         * @since 2021-09-10 16:21:52
         */
        public boolean ifDuplicate(String message) {
            int hash = StringUtils.nullToEmpty(message).replaceAll("\\d+", "").hashCode();

            // 超过1分钟清理
            if (System.currentTimeMillis() - lastClearTime
                    > TimeUnit.MINUTES.toMillis(this.warnProperties.getDuplicateTimeSpan())) {
                cacheTag.clear();
                lastClearTime = System.currentTimeMillis();
            }

            // 过长清理
            if (cacheTag.size() >= cacheMax) {
                cacheTag.clear();
            }

            if (!cacheTag.contains(hash)) {
                cacheTag.add(hash);
                return false;
            }

            return true;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy