日志系统的设计模式
origin: http://blog.csdn.net/chinainvent/article/details/7181573从事服务器程序开发的工程师们,几乎不可避免地需要使用到日志系统(Logging System)。如果从头开发一个服务器程序,我们有若干开源的日志系统可供选择,例如:Java语言中,Log4j是个不错的选择;Python语言中,有logging类;C语言中,有:
从事服务器程序开发的工程师们,几乎不可避免地需要使用到日志系统(Logging System)。
如果从头开发一个服务器程序,我们有若干开源的日志系统可供选择,例如:Java语言中,Log4j是个不错的选择;Python语言中,有logging类;C语言中,有:Log4c、libqb等。
这些开源的日志系统,几乎都使用到相同的设计模式,不同之处在于实现语言、实现方法,以及附加的一些额外功能。今天,我想介绍一下这个共通的设计模式,这会有助于我们用好这些开源的日志系统,或改进它们。
这些日志系统,包含三个要素:
- content: 日志的内容,通过在代码中调用日志接口,如log_printf("xxx"),向日志系统传递内容
- target: 日志的目标,即日志写到什么地方,例如可以同时写到stderr/syslog/xxx.log
- filter: 日志过滤规则,用于决定每一条日志能否输出到某个目标上
一个日志系统,可以定义多个日志目标;每个日志目标,有属于它自己的若干条过滤规则。
当日志系统,通过日志接口,接收到一条日志内容后(content),它做以下处理:
- for t in targets; {
- pass = False;
- for f in t.filters; {
- if content satisfies f; {
- pass = True;
- break;
- }
- }
- if (pass) {
- print content to t;
- }
- }
以上是伪代码,意思是,当日志系统收到一条日志,它会循环遍历所有target,并判断这条日志是否满足这些target的某条filter,如果满足则把日志内容输出到这个target上。
因为每条日志都需要经过这些步聚,所以日志系统的一个关键点,就是性能的优化问题。
从伪代码来看,外层的for循环是无法省略的。但内层的for循环,就是遍历t.filters的这一层循环,开源界的朋友们想到了一个好方法,可以把它优化为一个简单的条件判断。
他们是如何做到的呢?在libqb中,方法是这样的:
- 为每条日志,关联一个static的结构体,这个结构体定义在一个自定义的section中,这个结构体保存了这条日志的文件名、行号、日志优先级别等信息。
- 程序在启动时,通过扫描这个自定义的section,就可以获得所有日志的相关联的结构体信息,通过*预先*把这些结构体的信息与所有target的各自的filters进行匹配,从而可以计算出这些日志可以输出到哪些target上,然后在结构体中打上标志。
- 通过个“预处理”的过程,在程序运行时,就不必再进行日志与filter的匹配,直接通过相关联的结构体的标志位,即可判断能否输出到该target上。
更多推荐
所有评论(0)