天天看点

Adhesive框架系列文章--报警服务模块使用和实现

Adhesive框架的Mongodb数据服务模块提供了大量数据的存储功能。在有的时候,我们希望对数据量或是数据的某个值进行一个监控,并且在达到某个阀值之后进行报警。此时,可以使用报警服务模块进行邮件报警和短信报警。报警服务的实现其实很简单,定期检测数据量或数据的值,然后根据配置决定是否要报警,如果要的话,根据配置获取报警的接收者,然后进行相应的报警。现在先来看一下报警服务的配置,同样,打开配置后台可以在全局配置中找到报警服务的配置节点:

点击进去:
Adhesive框架系列文章--报警服务模块使用和实现

在这里依次介绍一下每一个配置:

1、状态数据的报警配置:这里配置了基于状态数据的报警配置。所谓状态信息,就是始终只有一条最新的数据代表了一个状态,报警也就是查看其中某个列的值,根据这个值来判断是否需要报警。

2、统计数据的报警配置:这里配置了基于统计数据的报警配置。所谓统计数据,就是一个时间间隔内有多少条数据写入,报警取决于数据量,而不是其中某一条数据的某个列的值。

3、接收者的配置:在这里把报警数据接收者分了组,使用组的概念来管理这些信息接收者。

4、短信服务的类别ID:这个是我们公司特有的短信通道的类别ID,不具有普适性。

5、邮件服务器的地址和帐号:在这里发送邮件使用的是Common模块中提供的JMail发送邮件的功能。

6、邮件标题和正文以及短信和日志消息的模板:这里配置的是,发送邮件的标题和正文、发消息的内容以及日志记录的内容的一个模板。其中有很多占位符:

1)配置的名字

2)列名

3)报警时间间隔

4)数据量

5)条件类型

6)阀值

一个典型的数据如下:

Adhesive.Test.Mvc错误日志监控 ItemCount 60秒 1400 MoreThan 100

7、发送邮件和短消息的时间间隔,发送邮件和短消息出错后的时间间隔:在这里我们还是使用了内存队列服务模块来发送邮件和短消息,这里配置的是正常情况下多少毫秒发送一次邮件或短消息,以及错误情况下多少时间后再一次尝试进行短消息和邮件的发送。

先来看一下报警接收者分组的配置:

Adhesive框架系列文章--报警服务模块使用和实现

在这里我们添加了一个名为测试的组:

Adhesive框架系列文章--报警服务模块使用和实现

对于每一个组都有如下的配置:

1、组名

2、是否开启邮件消息

3、是否开启手机短信消息

4、发送邮件消息的间隔,也就是在一定时间内只会发送一次消息

5、发送手机消息的间隔,同上。在有的时候我们可能会对相同的报警信息发送到两个组,第一个组允许1秒收一次消息,而第二个组是领导组,不希望有很多骚扰,那么可以配置时间长一点。

6、组内的接收者明细:

Adhesive框架系列文章--报警服务模块使用和实现

这里配置了一个用户,再点击进去查看明细:

Adhesive框架系列文章--报警服务模块使用和实现

对于每一个用户配置帐号、真实姓名、手机号码和邮箱地址。

然后,来看一下两种报警模式的配置,第一个是基于数据量的报警:

Adhesive框架系列文章--报警服务模块使用和实现

点击进入数据量统计配置节点之后可以看到在这里我们配置了一个叫错误日志监控的报警。也就是希望监控Adhesive.Test.Mvc这个表中错误日志的数据量,现在来看一下怎么通过灵活的配置完成这个功能:

Adhesive框架系列文章--报警服务模块使用和实现

首先,我们知道错误日志是存在Aic__Log这个数据库中的,那么我们指定数据库名为Aic__Log。然后我们希望针对Adhesive.Test.Mvc这个表进行报警,那么也需要配置相应的表名。然后我们希望配置1分钟内数据量超过100条则报警,那么需要把时间间隔配置为1分钟,把数据量阀值配置成100,把条件类型配置为MoreThan,这是一个枚举:

internal enum AlarmConditionType
    {
        LessThan = 1,
        LessThanAndEqualTo = 2,
        MoreThan = 3,
        MoreThanAndEqualTo = 4,
    }      

并且配置10秒进行一次检查,前1分钟是不是达到阀值。这里还有一个问题,就是我们希望只针对错误级别的日志进行报警,那么我们需要进一步配置数据过滤:

Adhesive框架系列文章--报警服务模块使用和实现

在这里配置Lev为4。可以对比下LogInfo的定义:

[MongodbPersistenceItem(MongodbIndexOption = MongodbIndexOption.Ascending, ColumnName = "Lev")]
        [MongodbPresentationItem(MongodbFilterOption = MongodbFilterOption.DropDownListFilter, DisplayName = "日志级别", ShowInTableView = true)]
        public LogLevel LogLevel { get; set; }      

其中看到,日志级别的列名为Lev,并且LogLevel值为4的级别是Error:

public enum LogLevel
    {
        None = 99,
        Debug = 1,
        Info = 2,
        Warning = 3,
        Error = 4
    }      

最后,看一下基于状态的配置:

Adhesive框架系列文章--报警服务模块使用和实现

在这里我们希望监控Mongodb服务端内存队列中当前项的数量,如果数量超过100则报警(内存中有100条剩余的数据来不及提交到数据库)。

Adhesive框架系列文章--报警服务模块使用和实现

基本的配置和统计量的配置差不多,只不过注意这里的列名是模糊匹配的:

Adhesive框架系列文章--报警服务模块使用和实现

对比一下State__MongodbServer的定义,也就是任意一个内存队列的CurrentItemConut超过100都会报警。之所以能这样是因为我们Mongodb存储字典是树形结构的。

介绍了报警服务的配置之后,我们来看其中的一个最关键的实现,也就是服务的初始化过程:

internal static void Init()
        {
            mailService.Init(AlarmConfiguration.GetConfig().MailSmtp, AlarmConfiguration.GetConfig().MailUsername, AlarmConfiguration.GetConfig().MailPassword);
            mobileService.Init(AlarmConfiguration.GetConfig().MobileCategoryId);

            mailMemoryQueueService.Init(new MemoryQueueServiceConfiguration("AlarmService_MailQueue", mailService.Send)
            {
                ConsumeItemCountInOneBatch = 1,
                ConsumeIntervalMilliseconds = AlarmConfiguration.GetConfig().MailMessageInerval,
                ConsumeIntervalWhenErrorMilliseconds = AlarmConfiguration.GetConfig().MailMessageErrorInerval,
                ConsumeErrorAction = MemoryQueueServiceConsumeErrorAction.EnqueueTwiceAndLogException
            });
            mobileMemoryQueueService.Init(new MemoryQueueServiceConfiguration("AlarmService_MobileQueue", mobileService.Send)
            {
                ConsumeItemCountInOneBatch = 1,
                ConsumeIntervalMilliseconds = AlarmConfiguration.GetConfig().MobileMessageInerval,
                ConsumeIntervalWhenErrorMilliseconds = AlarmConfiguration.GetConfig().MobileMessageErrorInerval,
                ConsumeErrorAction = MemoryQueueServiceConsumeErrorAction.EnqueueTwiceAndLogException
            });
            var config = AlarmConfiguration.GetConfig();
            foreach (var item in config.AlarmConfigurationByStatistics)
            {
                var alarmServiceState = new AlarmServiceState
                {
                    AlarmConfigurationItemName = item.Key,
                    AlarmServiceStateItems = new Dictionary<string, AlarmServiceStateItem>(),
                };
                item.Value.AlarmReceiverGroupNames.Values.Each(groupName =>
                {
                    alarmServiceState.AlarmServiceStateItems.Add(groupName, new AlarmServiceStateItem
                    {
                        ReceiverGroupName = groupName,
                        AlarmReceiverGroupLastMailMessageTime = DateTime.MinValue,
                        AlarmReceiverGroupLastMobileMessageTime = DateTime.MinValue,
                    });
                });
                var interval = item.Value.CheckTimeSpan;
                var timer = new System.Threading.Timer(CheckActionForStatistics, item.Key, interval, interval);
                alarmServiceState.CheckTimer = timer;
                alarmServiceStates.Add(alarmServiceState);
            }

            foreach (var item in config.AlarmConfigurationByStates)
            {
                var alarmServiceState = new AlarmServiceState
                {
                    AlarmConfigurationItemName = item.Key,
                    AlarmServiceStateItems = new Dictionary<string, AlarmServiceStateItem>(),
                };
                item.Value.AlarmReceiverGroupNames.Values.Each(groupName =>
                {
                    alarmServiceState.AlarmServiceStateItems.Add(groupName, new AlarmServiceStateItem
                    {
                        ReceiverGroupName = groupName,
                        AlarmReceiverGroupLastMailMessageTime = DateTime.MinValue,
                        AlarmReceiverGroupLastMobileMessageTime = DateTime.MinValue,
                    });
                });
                var interval = item.Value.CheckTimeSpan;
                var timer = new System.Threading.Timer(CheckActionForState, item.Key, interval, interval);
                alarmServiceState.CheckTimer = timer;
                alarmServiceStates.Add(alarmServiceState);
            }
        }
    }      

我们知道在报警服务模块中,我们也是通过内存队列服务来进行邮件和短信数据发送的,那么我们首先是初始化两个内存队列。

然后,我们读取配置,分别为基于统计数据的报警和基于状态的报警初始化后台的定时器,每一种配置一个定时器。定时器的执行间隔就是前面提到的CheckTimeSpan。而我们的代码中也定义了alarmServiceStates字段作为根:

private static List<AlarmServiceState> alarmServiceStates = new List<AlarmServiceState>();      

作者:

lovecindywang

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。