Adhesive框架系列文章--应用程序信息中心模块使用实践

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
性能测试 PTS,5000VUM额度
日志服务 SLS,月写入数据量 50GB 1个月
简介: 应用程序信息中心模块提供了日志、异常、性能、状态四大服务。来看一下最新的日志服务定义: void Debug(string message); void Debug(string moduleName, string message); ...

应用程序信息中心模块提供了日志、异常、性能、状态四大服务。来看一下最新的日志服务定义:

        void Debug(string message);

        void Debug(string moduleName, string message);

        void Debug(string categoryName, string subcategoryName, string message);

        void Debug(string moduleName, string categoryName, string subcategoryName, string message);

        void Debug(string message, ExtraInfo extraInfo);

        void Debug(string moduleName, string message, ExtraInfo extraInfo);

        void Debug(string categoryName, string subcategoryName, string message, ExtraInfo extraInfo);

        void Debug(string moduleName, string categoryName, string subcategoryName, string message, ExtraInfo extraInfo);

和之前版本的Adhesive相比,最新的日志服务增加了模块名,我们来看一下这些重载的应用范围:

1、对于基础模块,推荐定义模块名、大类和小类。这三个参数是级联的:

        [MongodbPresentationItem(MongodbCascadeFilterOption = MongodbCascadeFilterOption.LevelOne, DisplayName = "模块名", ShowInTableView = true)]
        [MongodbPersistenceItem(MongodbIndexOption = MongodbIndexOption.Ascending, ColumnName = "MDN")]
        public string ModuleName { get; set; }

        [MongodbPresentationItem(MongodbCascadeFilterOption = MongodbCascadeFilterOption.LevelTwo, DisplayName = "大类", ShowInTableView = true)]
        [MongodbPersistenceItem(MongodbIndexOption = MongodbIndexOption.Ascending, ColumnName = "C")]
        public string CategoryName { get; set; }

        [MongodbPresentationItem(MongodbCascadeFilterOption = MongodbCascadeFilterOption.LevelThree, DisplayName = "小类", ShowInTableView = true)]
        [MongodbPersistenceItem(MongodbIndexOption = MongodbIndexOption.Ascending, ColumnName = "SC")]

如果没有定义模块名,那么使用的是“主模块”,也就表明这个日志是主程序的日志,而不是其中某一个模块的日志。

image

在框架内部的所有模块的日志都定义了模块名,这样我们很容易区分日志的来源,比如:

 AppInfoCenterService.LoggingService.Warning(MongodbServiceConfiguration.ModuleName, "InternalGetMongodbData", typeFullName,
                           string.Format("遇到重复的列,类型:{0},列名:{1}", typeFullName, columnName));

这是我们的Mongodb数据服务记录的日志,我们除了定义模块名,还使用方法名来作为大类,使用数据的类型名作为小类。以便我们搜索日志。

对于非基础的模块,无需指定模块名,至于大类小类可以指定,比如可以把大类设置为页面名,把小类设置为方法名。当然,对于主模块,大类默认就是页面名或是类名。

2、请善于利用ExtraInfo,我们知道日志的消息是不允许搜索的,如果需要搜索请通过ExtraInfo,比如:

                    AppInfoCenterService.LoggingService.Info(AlarmConfiguration.ModuleName, "AlarmService", "InternalHandleAlarm",
                        string.Format("{0} {1} <= {2} 没达到邮件发送条件", logMessgae, mailPastTime.ToString(), group.MailMessageIntervalTimeSpan.ToString()),
                        new ExtraInfo
                        {
                            DropDownListFilterItem1 = "没达到邮件发送条件",
                            DropDownListFilterItem2 = configItem.ConfigName,
                        });

在这里是一条报警服务的日志,我们把ExtraInfo中的两个下拉框设置都设置了值,这样我们就可以搜索了:

image

 

同样,异常服务的接口中也允许我们指定模块名、大类、小类以及ExtraInfo:

        void Handle(Exception exception);

        void Handle(string moduleName, Exception exception);

        void Handle(string categoryName, string subcategoryName, Exception exception);

        void Handle(string moduleName, string categoryName, string subcategoryName, Exception exception);

        void Handle(Exception exception, string description);

        void Handle(string moduleName, Exception exception, string description);

        void Handle(string categoryName, string subcategoryName, Exception exception, string description);

        void Handle(string moduleName, string categoryName, string subcategoryName, Exception exception, string description);


        void Handle(Exception exception, ExtraInfo extraInfo);

        void Handle(string moduleName, Exception exception, ExtraInfo extraInfo);

        void Handle(string categoryName, string subcategoryName, Exception exception, ExtraInfo extraInfo);

        void Handle(string moduleName, string categoryName, string subcategoryName, Exception exception, ExtraInfo extraInfo);

        void Handle(Exception exception, string description, ExtraInfo extraInfo);

        void Handle(string moduleName, Exception exception, string description, ExtraInfo extraInfo);

        void Handle(string categoryName, string subcategoryName, Exception exception, string description, ExtraInfo extraInfo);

        void Handle(string moduleName, string categoryName, string subcategoryName, Exception exception, string description, ExtraInfo extraInfo);  

在框架内部的各个模块中我们捕获的异常也遵循这个原则,就是指定模块名,而不是使用主模块:

  ex.Handle(MongodbServerConfiguration.ModuleName, "MongodbServerMaintainceCenter", "列", "创建索引出错", new ExtraInfo
                                        {
                                            DisplayItems = new Dictionary<string, string>
                                            {
                                                {"数据库名", databaseName },
                                                {"表名", collectionName },
                                                {"列名" , indexColumnDescription.ColumnName }
                                            }
                                        });

这里,还注意到description这个参数,我们往往可以把它设置为对异常的描述,在这里可以把一些参数信息写在描述中,也可以使用ExtraInfo的DisplayItems。在上面那个异常中我们使用了ExtraInfo,因为KeyValue更清晰,再来看看另外一个例子:

ex.Handle(AppInfoCenterService.ModuleName, ServiceName, "Report", string.Format("调用汇报状态回调方法出错,类型:{0}", configuration.TypeFullName));

异常的描述是开发人员自己提供的,往往比原始的Message更容易看出问题,比如NullReferenceException的异常消息往往对我们没用,只有靠我们自己:

image

 

第三个服务是状态服务,在使用上需要注意的是,由于状态服务其实是一个后台线程,请以静态方式全局为一种状态定义一个状态服务,比如:

    public class Global : System.Web.HttpApplication
    {
        private static IStateService testStateService;
        public static int stateValue = 100;
        protected void Application_Start(object sender, EventArgs e)
        {
            Adhesive.Common.AdhesiveFramework.Start();
            testStateService = AppInfoCenterService.StateService;
            testStateService.Init(new StateServiceConfiguration("Adhesive.Test.WebApp.TestState", () =>
            {
                return new List<BaseInfo> { new TestState
                {
                    StateValue = stateValue,
                } };
            }));
        }
...

光是代码方式定义了状态服务还不够,还需要在配置服务中根据类型完整名进行相应的定义:

image

要注意两点:

1、类型完整名要和代码中写的保持一致

2、状态服务属于信息中心模块,信息中心模块是私有的不是全局的配置,请看图中的路径

 

第四个服务是性能计算服务,使用方式如下:

       protected void Performance_Click(object sender, EventArgs e)
        {
            AppInfoCenterService.PerformanceService.StartPerformanceMeasure("性能测试1");
            for (int i = 0; i < 5; i++)
            {
                MethodA();
                MethodB();
            }
        }

        private void MethodA()
        {
            Thread.Sleep(int.Parse(SleepTime.Text));
            AppInfoCenterService.PerformanceService.SetPerformanceMeasurePoint("性能测试1", "MethodA");
        }

        private void MethodB()
        {
            for (int i = 0; i < int.Parse(CpuTime.Text); i++)
            {
                var d = 10000000;
                Math.Cos(d);
                Math.Sin(d);
                Math.Log10(d);
                Math.Sqrt(d);
            }
            AppInfoCenterService.PerformanceService.SetPerformanceMeasurePoint("性能测试1", "MethodB");
        }

这里需要注意几个问题:

1、StartPerformanceMeasure应该在要统计的代码一开始写

2、SetPerformanceMeasurePoint应该在要统计的方法的最后写

3、对于同一个性能统计,SetPerformanceMeasurePoint和StartPerformanceMeasure中的性能测试名需要保持一致

 

总之一定,Adhesive的信息中心模块只是提供了一个信息收集的渠道,如果希望自己的程序可以尽快排查定位问题,那么需要遵循几个实践原则:

1、不吞吃所有异常,都调用Handle方法来处理异常,Handle不意味万能,在必要的时候throw出异常

2、合理利用各种日志服务来记录各种日志,合理区分各种LogLevel,一旦日志过多,我们可以根据LogLevel来分别开关,比如:

image

image

在这里我们通过定义一个新的日志策略,来关闭报警服务模块Debug日志的远程记录功能

并且,我们也可以调整日志记录的详细程序,比如我们希望报警模块的Info级别的日志包含信息策略为None,而不是主模块默认的Simple:

image

条件中限制了LogLevel是Info而ModuleName是报警服务模块:

image

3、尽量通过模块、分类来区分各种日志和异常

4、尽量在日志的消息、异常的描述中体现多一点信息,而不是简单的一些“出错”字样,但要注意方法的重载,不要把分类写到描述,把描述写到分类

5、合理利用ExtraInfo来提供数据的筛选功能,或提交参数信息

6、针对信息中心模块自己记录的网站未处理异常、应用程序域未处理异常设置基于统计的报警策略

7、可以针对信息中心模块自己记录的网站请求状态等状态设置基于状态的报警策略

8、合理利用信息中心模块的代码性能统计服务来排查性能问题

9、对于需要索引的项,比如模块名、大类、小类,以及ExtraInfo中的一些过滤字段,在数据库中是做索引的,因此这些字段应该是枚举数量控制在一定范围,比如100之内的,如果它们的变化范围达到几千甚至几万,那么就不适合了

作者: lovecindywang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
7月前
|
XML JavaScript Java
技术经验分享:Asea——轻量级的AS3模块配置与加载管理库
技术经验分享:Asea——轻量级的AS3模块配置与加载管理库
50 0
|
5月前
|
Java Maven 数据库
一文教会你如何进行Rest微服务构建 案例工程模块。教会你如何创建父子工程
这篇文章介绍了如何在微服务架构中创建父子工程模块,并通过RESTful服务的方式构建微服务通用案例,包括服务提供者和消费者的基本实现,以及数据库的创建和测试服务的步骤。
一文教会你如何进行Rest微服务构建 案例工程模块。教会你如何创建父子工程
|
6月前
|
移动开发 小程序 JavaScript
跨端技术问题之转Web运行时的“框架”模块主要负责什么功能
跨端技术问题之转Web运行时的“框架”模块主要负责什么功能
|
8月前
|
资源调度 供应链 监控
深入探究:ERP系统的核心模块解析
深入探究:ERP系统的核心模块解析
372 0
|
JavaScript Go API
全面拥抱 FastApi — 多应用程序项目结构规划
全面拥抱 FastApi — 多应用程序项目结构规划
|
JavaScript 前端开发 数据库
Unity3d(webGL)构建数字孪生小案例(包含完整的数据交互体系)附赠完整代码
Unity3d(webGL)构建数字孪生小案例(包含完整的数据交互体系)附赠完整代码,请关注公众号:拼搏的小浣熊,获取简化版的代码!
|
前端开发 算法 Java
合工大企业实训-计划管理模块-后端搭建
合工大企业实训-计划管理模块-后端搭建
114 0
|
Swift iOS开发
SwiftLint 自动规范代码工具(下)
SwiftLint 自动规范代码工具(下)
617 0
SwiftLint 自动规范代码工具(下)
|
人工智能 Java 编译器
SwiftLint 自动规范代码工具(上)
SwiftLint 自动规范代码工具(上)
511 0
SwiftLint 自动规范代码工具(上)

热门文章

最新文章