谈谈日志系统开发设计

    一、重要性( 为什么要设计日志(LOG)系统?)
    日志(LOG)系统在整个系统架构中的重要性可以称得上基础的基础,但是这一点,都容易被大多数人所忽视。因为日志(LOG)在很多人看来只是printf。在系统运行期间,是很难step by step的,所以只能根据系统的运行轨迹来推断错误出现的位置,这往往也是唯一的资料,特别是在高可靠性的情况下。
    从更大方面的范围来说,日志(LOG)系统是运营维护的范畴。但小的方面来说,这是必须的调试的手段。在多年的开发经验来看,日志(LOG)系统必须被我们重视的。

    二、 解决问题( 怎么设计日志(LOG)系统 )
    日志(LOG)系统的主要解决的问题是记录系统的运行轨迹,在这个基础上,进行跟踪分析错误,审计系统运行流程。在高可靠的系统中,是不允许系统运行终止的。日志(LOG)系统的内容可以分为2类,一类可是业务级别的日志(LOG),主要供终端用户来分析他们业务过程;另一类是系统级别的日志(LOG),供开发者维护系统的稳定。
    由于日志(LOG)系统的数据输出量比较大,所以不能不考虑对整个系统性能的影响。从另外一方面来看,海量的日志(LOG)内容有时候并不件好事,因为,很容易覆盖真实问题的蛛丝马迹。也增加日志(LOG)阅读者信息检索的困难。
    日志(LOG)系统的设计,必须解决几个问题:
    1、使用方便,包括开发和信息检索。
    2、组织合理,日志(LOG)内容被有效的组织起来。有助于基于日志(LOG)内容的分析。
    3、过程重现,这个目标其实对开发者来说是最重要的。基于日志(LOG)的分析,最重要的是重现当时运行的过程。
    4、可控制性,允许用户进行干预,特别是运行期的干预。比如关闭某些内容,或者重定向内容的输入目标点。

    三、系统构成 (日志(LOG)系统是什么?)
    一个日志(LOG)系统根据他的过程,可以分为日志(LOG)来源,系统控制,日志(LOG)输出,【日志(LOG)存储】。根据这个过程,我们可以将整个系统分为4个模块,并加以抽象。

    1、日志(LOG)来源
    日志(LOG)内容可以来源于任何其他系统,但对日志(LOG)系统来说,这是个格式化的缓冲区。对于日志(LOG)系统来说,任何内容都是合法的。最重要的是,日志(LOG)系统必须提供一个简单的规则,为后续的管理和检索提供方便性和灵活性。在传统的printf格式中,是很难维护一个格式化的日志(LOG)输出。文本方式对人来说阅读方便,但不容易检索,特别是在大量日志(LOG)的情况下,更不好维护了。
    2、日志(LOG)控制
    系统控制的重点在于控制日志(LOG)内容在日志(LOG)系统中的流转过程。比如日志(LOG)输出目的地,比如日志(LOG)的输出级别。我们在apache的Logging项目中曾经看到,他们提供了一个和平时不太一样的输出目的地,telnet。这和传统的stdout、stderr、syslog有很大的区别,便于远程管理,更大的潜力在于,可以在运行期,通过登录telnet来动态调整系统环境配置。
    3、日志(LOG)输出
    日志(LOG)在控制台输出是比较常见的,但如何考虑为系统的可靠性提供支持,以及大量日志(LOG)内容的情况下,这个一般不予考虑的。在控制台输出的,只会是非常核心的内容或者是致命的错误,况且,在有些情况下,不一样会有控制台。我们一般在这种情况下,都倾向于将日志(LOG)输出到文件。但对一个完善的日志(LOG)系统,日志(LOG)输出和日志(LOG)存储又是有区别的。日志(LOG)存储是日志(LOG)输出到文件的一种方式。日志(LOG)输出也是日志(LOG)控制的一个内容。
    4、日志(LOG)存储
    日志(LOG)存储在很多小型系统往往并不需要关注,一个可靠性要求很高的系统中,对日志(LOG)存储却是极为苛刻。就是在现在的数据库系统中,也必须依赖日志(LOG)的存在,来还原操作。

    四、日志(LOG)内容 (???!!!!)
    1、内容分级
    在LINUX的SYSLOG中,对日志(LOG)内容进行分级,将分为8个级别,如下:

    #define LOG_EMERG 0
    #define LOG_ALERT 1
    #define LOG_CRIT 2
    #define LOG_ERR 3
    #define LOG_WARNING 4
    #define LOG_NOTICE 5
    #define LOG_INFO 6
    #define LOG_DEBUG 7

    这样,我们只需要设置一个全局变量,监控日志(LOG)内容输出级别。当产生日志(LOG)内容的级别比输出级别更优先时,将被记录下来,否则被简单的忽略。这种方式,很容易控制日志(LOG)的输出内容。在WIN32平台下,有分类的功能,但是没有分级。但实际上也有个问题,就是只能控制一个输出范围,如果想只输出特定类的日志(LOG)内容,在策略上,还是比较麻烦的。
    2、内容分类
    在LINUX的SYSLOG中,不但对日志(LOG)内容有分级,同样也有分类,主要是根据日志(LOG)内容的来源,如下:

    #define LOG_KERN (0<<3)
    #define LOG_USER (1<<3)
    #define LOG_MAIL (2<<3)
    #define LOG_DAEMON (3<<3)
    #define LOG_AUTH (4<<3)
    #define LOG_SYSLOG (5<<3)
    #define LOG_LPR (6<<3)
    #define LOG_NEWS (7<<3)
    #define LOG_UUCP (8<<3)
    #define LOG_CRON (9<<3)
    #define LOG_AUTHPRIV (10<<3)
    #define LOG_FTP (11<<3)

    在WIN32平台下的事件管理器也是有相应的功能,只是有部分区别。WIN32的系统日志(LOG)被分为安全性、应用程序、系统等几类。每类都有几个固定的字段,日志(LOG)内容是以文本方式被保存的。分类的主要依据也是日志(LOG)内容的来源。

    3、内容格式
    虽然内容的分级和分类在很大的程度上,对日志(LOG)内容进行归类,但这远远不够。这个规则的粒度相当粗糙。也就是说,针对特定级别特定类的日志(LOG)内容也会是相当地庞大。因此有必要针对日志(LOG)内容在更小粒度的划分,就是内容格式的设计。内容格式的设计上,有个很致命的问题,就是内容的多样性,很难用一个统一的格式来限定内容输出。对于动态内容的格式话,其实我们也有几个现成方案值得借鉴。
    首先、XML在格式化多样性内容方面具有相当大的灵活性,不过他也有个致命的弱点,就是解析内容时,具有相当大的时间复杂度。
    其实、TDS协议是SYBASE数据库在输出DBMS结果给客户端时,数据流的格式。他允许在一个流中存在不同类表的数据,比如多个不同结果字段的游标。在灵活性方面不如XML,但速度要快于XML。
    最后、每个内容块都遵循同样的格式,这种方式,灵活性最差,但要简单多了。整个日志(LOG)内容相当于一个固定结构的表。
    从笔者的角度出发,倾向于以TDS的格式为基础,引进XML的某些特性,来设计出一个内容格式。

    4、内容边界
    日志(LOG)系统可能需要将各种各种格式的日志(LOG)内容统一存储在一起,这些内容同样可能是不同的大小,因此我们需要确认每个内容边界,否则极有可能混淆每个内容的确切内容。内容边界是日志(LOG)系统设计的一个最基本细节,否则这个日志(LOG)系统将是不可能。没法确切区分每个日志(LOG)内容,后续的分析就没法是实现了。内容边界的设计,在日志(LOG)存储系统之前就必须是明确的。