The default alarm rule extension of the alarm system QuickAlarm

The default alarm rule extension of the alarm system QuickAlarm

This article is mainly to expand the default alarm rules to make it more friendly to support multiple alarm methods at the same time

Extensions follow two principles

  • Does not affect the original configuration file format
  • Simplify rule parsing complexity

I. Expansion of configuration files

First look at the original configuration file

{
    "default": {
        "level": "NONE",
        "autoIncEmergency": true,
        "max": 30,
        "min": 3,
        "threshold": [
            {
                "level": "LOG",
                "threshold": 5,
                "users": [
                    "yihui",
                    "erhui"
                ]
            }
        ],
        "users": [
            "yihui"
        ]
    },
    "NPE,SELFDEFINE": {
        "level": "LOG",
        "autoIncEmergency": false,
        "max": 30,
        "min": 0,
        "threshold": [
            {
                "level": "SMS",
                "threshold": 20,
                "users": [
                    "345345345345",
                    "123123123123"
                ]
            },
            {
                "level": "WEIXIN",
                "threshold": 10,
                "users": [
                    "小灰灰Blog",
                    "greyBlog"
                ]
            }
        ],
        "users": [
            "yihui"
        ]
    }
}

We hope to be able to support multiple alarm methods to be selected at the same time, then in the above configuration, it is obviously inappropriate to define only one threshold parameter in the threshold. The main problem is that

  • Single threshold, no crossover between different alarm modes is allowed
  • When the threshold values ​​of the two alarm modes are equal, which one is selected is unpredictable

So our goal is to add a value max that specifies the upper limit to the above parameters

{
    "default": {
        "level": "NONE",
        "autoIncEmergency": true,
        "max": 30,
        "min": 3,
        "threshold": [
            {
                "level": "LOG",
                "threshold": 5,
                "users": [
                    "yihui",
                    "erhui"
                ]
            }
        ],
        "users": [
            "yihui"
        ]
    },
    "NPE,SELFDEFINE": {
        "level": "LOG",
        "autoIncEmergency": false,
        "max": 30,
        "min": 0,
        "threshold": [
            {
                "level": "SMS",
                "threshold": 20,
                "users": [
                    "345345345345",
                    "123123123123"
                ]
            },
            {
                "level": "WEIXIN",
                "threshold": 10,
                "users": [
                    "小灰灰Blog",
                    "greyBlog"
                ]
            }
        ],
        "users": [
            "yihui"
        ]
    },
    "ZZZ": {
        "level": "LOG",
        "autoIncEmergency": true,
        "max": 30,
        "min": 3,
        "threshold": [
            {
                "level": "SMS",
                "threshold": 20,
                "max": 27,
                "users": [
                    "345345345345",
                    "123123123123"
                ]
            },
            {
                "level": "WEIXIN",
                "threshold": 10,
                "users": [
                    "yihui",
                    "erhui"
                ]
            },
            {
                "level": "EMAIL",
                "threshold": 9,
                "max": 14,
                "users": [
                    "[email protected]",
                    "[email protected]"
                ]
            }
        ],
        "users": [
            "[email protected]"
        ]
    }
}

After the above changes, it is equivalent that each alarm mode can define its own interval, so multiple alarm modes are allowed to have the intersection of intervals, and the count in the intersection interval means that the multiple modes are selected.

II. Extended Implementation Support

Judging from the changes in the configuration file, the changes are very small, only a new parameter is added, and this parameter is not required, then the corresponding do should be

public class BasicAlarmThreshold {

    private String level;

    /**
     * 启用定义的报警方式的阀值下限,
     *
     * 当报警计数 count >= min
     *   - max 非null, count < max 则选择本报警方式; 
    *       count >= max 则不选择本报警方式
     *   - max 为null(即表示为定义时),
     *      则max赋值为:恰好大于 min 的 {@link BasicAlarmThreshold#threshold}值
     *
     */
    private int threshold;


    /**
     * 报警上限值,注意这是包装类型,允许为null
     */
    private Integer max;

    private List<String> users;
}

Then, along the way, optimize our mapping rules and map the DO objects of the configuration rules to business objects

The main mapping rules are as follows

/**
 * 将配置项转换为业务DO对象, 会做一些兼容, 保证 level. min, max, users, thresholds 都不会为null
 *
 * @param basicAlarmConfig
 * @return
 */
private static AlarmConfig parse2BizConfig(BasicAlarmConfig basicAlarmConfig) {
    if (basicAlarmConfig.getUsers() == null || basicAlarmConfig.getUsers().isEmpty()) { // 如果没有填写用户, 则直接抛弃
        return null;
    }

    AlarmConfig alarmConfig = new AlarmConfig();

    // 如果配置的报警类型是异常的, 则下面会兼容一把,设置为 NONE, 避免因为配置的原因导致系统异常
    alarmConfig.setExecutor(SimpleExecuteFactory.getExecute(basicAlarmConfig.getLevel()));
    alarmConfig.setAutoIncEmergency(basicAlarmConfig.isAutoIncEmergency());
    // 报警用户, 要求用户必须存在
    alarmConfig.setUsers(basicAlarmConfig.getUsers());
    // 报警上限, 如果用户没有填写,采用默认的(因为短信报警按条数要钱, 没必要一直无上限的报)
    alarmConfig.setMaxLimit(basicAlarmConfig.getMax() == null ? AlarmConfig.DEFAULT_MAX_NUM : basicAlarmConfig.getMax());
    // 报警下限, 如果用户没有填写, 采用默认的最小值0
    alarmConfig.setMinLimit(basicAlarmConfig.getMin() == null ? AlarmConfig.DEFAULT_MIN_NUM : basicAlarmConfig.getMin());


    // 获取配置中的阀值列表,并排序
    List<BasicAlarmThreshold> basicAlarmThresholdList = basicAlarmConfig.getThreshold();
    if(basicAlarmThresholdList == null) {
        basicAlarmThresholdList = Collections.emptyList();
    }
    basicAlarmThresholdList.sort(Comparator.comparingInt(BasicAlarmThreshold::getThreshold));

    List<AlarmThreshold> alarmThresholdList = new ArrayList<>(basicAlarmThresholdList.size() + 2);
    AlarmThreshold tmpAlarmThreshold;
    BasicAlarmThreshold tmpBasicAlarmThreshold;
    boolean containDefaultExecute = false;
    for (int i = 0; i < basicAlarmThresholdList.size(); i++) {
        tmpBasicAlarmThreshold = basicAlarmThresholdList.get(i);
        tmpAlarmThreshold = new AlarmThreshold();
        tmpAlarmThreshold.setExecutor(SimpleExecuteFactory.getExecute(tmpBasicAlarmThreshold.getLevel()));
        tmpAlarmThreshold.setUsers(tmpBasicAlarmThreshold.getUsers());
        tmpAlarmThreshold.setMin(tmpBasicAlarmThreshold.getThreshold());
        if (tmpBasicAlarmThreshold.getMax() == null || tmpBasicAlarmThreshold.getMax() <= tmpBasicAlarmThreshold.getThreshold()) {
            if (i == basicAlarmThresholdList.size() - 1) { // 最后一个,则使用默认的上限阀值
                tmpAlarmThreshold.setMax(alarmConfig.getMaxLimit());
            } else {
                tmpAlarmThreshold.setMax(basicAlarmThresholdList.get(i + 1).getThreshold());
            }
        } else {
            tmpAlarmThreshold.setMax(tmpBasicAlarmThreshold.getMax());
        }

        if (!containDefaultExecute) {
            containDefaultExecute = tmpBasicAlarmThreshold.getLevel().equals(basicAlarmConfig.getLevel());
        }


        alarmThresholdList.add(tmpAlarmThreshold);
    }


    int thresholdSize = alarmThresholdList.size();
    if (thresholdSize == 0) { // 没有配置阀值列表,直接使用默认
        tmpAlarmThreshold = new AlarmThreshold();
        tmpAlarmThreshold.setExecutor(alarmConfig.getExecutor());
        tmpAlarmThreshold.setUsers(alarmConfig.getUsers());
        tmpAlarmThreshold.setMin(alarmConfig.getMinLimit());
        tmpAlarmThreshold.setMax(alarmConfig.getMaxLimit());
        alarmThresholdList.add(tmpAlarmThreshold);
    } else if (!containDefaultExecute) { // 不包含时默认时,补全
        tmpAlarmThreshold = new AlarmThreshold();
        tmpAlarmThreshold.setExecutor(alarmConfig.getExecutor());
        tmpAlarmThreshold.setUsers(alarmConfig.getUsers());
        tmpAlarmThreshold.setMin(alarmConfig.getMinLimit());
        tmpAlarmThreshold.setMax(alarmThresholdList.get(0).getMin());
        alarmThresholdList.add(0, tmpAlarmThreshold);

        if (alarmThresholdList.get(thresholdSize).getMax() < alarmConfig.getMaxLimit()) {
            tmpAlarmThreshold = new AlarmThreshold();
            tmpAlarmThreshold.setExecutor(alarmConfig.getExecutor());
            tmpAlarmThreshold.setUsers(alarmConfig.getUsers());
            tmpAlarmThreshold.setMin(alarmThresholdList.get(thresholdSize).getMax());
            tmpAlarmThreshold.setMax(alarmConfig.getMaxLimit());
            alarmThresholdList.add(tmpAlarmThreshold);
        }
    }


    alarmConfig.setAlarmThreshold(alarmThresholdList);
    return alarmConfig;
}

In the logic of mapping to business objects, AlarmThresholdthe order in the list is directly guaranteed to be the final demand order, and the mapping rule is

/**
 *  如果配置的basicAlarmThresholdList列表中包含默认的报警方式
 *    - 则报警方式完全按照basicAlarmThresholdList的定义来
 *    - eg: 默认报警为 Log, min=5, max=30
 *    -       basicAlarmThresholdList 中定义为  : { Log, min=6 }, { Email, min=8 }, { WeiXin, min=10, max=16 }, { SMS, min=14, max=26 }
 *    - 则转换后的 alarmThresholdList为:
 *    -     { Log, min=6, max=8 }, { Email, min=8, max=10 }, { WeiXin, min=10, max=16 }, { SMS, min=14, max=26 }
 *    -       count : [6, 8)  Log
 *    -       count : [8, 10) Email
 *    -       count : [10, 16) WeiXin
 *    -       count : [14, 26) SMS
 *
 *  如果不包含默认报警方式
 *    - 则需要补全最外层定义的Min-Max区间中的空余位
 *    - eg:   默认报警为 Log, min=5, max=30
 *    -       basicAlarmThresholdList 中定义为  : { Email, min=8 }, { WeiXin, min=10, max=16 }, { SMS, min=14, max=26 }
 *    - 则转换后的 alarmThresholdList为:
 *    -       { Log, min=5, max=8 }, { Email, min=8, max=10 }, { WeiXin, min=10, max=16 }, { SMS, min=14, max=26 }, { Log, min=26, max=30 }
 *    -       count : [5, 8)  Log
 *    -       count : [8, 10) Email
 *    -       count : [10, 16) WeiXin
 *    -       count : [14, 26) SMS
 *    -       count : [26, 30) Log
 *
 *
 *    上面改造后,很容易得知,支持多重报警方式同时工作,即当技术为14,15 时,同时发起WeiXin和SMS报警
 */

Correspondingly, you can get rid of the Executor selection logic that was not very easy to understand. The corresponding code is

// com.hust.hui.alarm.core.execut.AlarmExecuteSelector#getExecute
public static List<ExecuteHelper> getExecute(final AlarmConfig alarmConfig, int count) {
    // 未达到报警的下限 or 超过报警的上限时
    if (count < alarmConfig.getMinLimit() || count > alarmConfig.getMaxLimit()) {
        return Collections.singletonList(new ExecuteHelper(SimpleExecuteFactory.getExecute(NoneExecute.NAME), alarmConfig.getUsers()));
    }


    // 未开启报警升级, 直接返回
    if (!alarmConfig.isAutoIncEmergency()) {
        return Collections.singletonList(new ExecuteHelper(alarmConfig.getExecutor(), alarmConfig.getUsers()));
    }

    if (count < alarmConfig.getAlarmThreshold().get(0).getMin()) {
        // 未达到报警的下限
        return Collections.singletonList(new ExecuteHelper(SimpleExecuteFactory.getExecute(NoneExecute.NAME), alarmConfig.getUsers()));
    }

    List<ExecuteHelper> list = new ArrayList<>();
    for(AlarmThreshold alarmThreshold: alarmConfig.getAlarmThreshold()) {
        if (alarmThreshold.getMin() <= count && count < alarmThreshold.getMax()) {
            list.add(new ExecuteHelper(alarmThreshold.getExecutor(), alarmThreshold.getUsers()));
        }
        
        if(alarmThreshold.getMin() > count) {
            break;
        }
    }
    return list;
}

III. Other

Related blog posts

  1. Alarm system QuickAlarm general outline
  2. Design and Realization of Alarm Actuator of Alarm System QuickAlarm
  3. Setting and loading of the alarm rules of the alarm system QuickAlarm
  4. Analysis of the alarm rules of the alarm system QuickAlarm
  5. Frequency Statistics and Interface Package of Alarm System QuickAlarm
  6. Alarm System QuickAlarm User Manual

Project: QuickAlarm

Personal blog: Z+|blog

A personal blog based on hexo + github pages, recording all blog posts in study and work, welcome to visit

statement

It is not as good as a letter of faith, the content has been posted, it is purely the opinion of the family, because of my average ability and limited knowledge, if you find bugs or have better suggestions, you are always welcome to criticize and correct

My Weibo address: Little Gray Blog

Personal QQ: 3302797840

Scan attention

QrCode

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325477123&siteId=291194637