设计概要
Boost.Log的设计致力于模块化和高扩展性。她同时支持窄字符和宽字符日志。窄字符和宽字符logger的功能类似,故以下文档大都只对窄字符接口展开描述。
日志库由3层抽象组成:日志数据收集层,收集数据处理层,中心路由层(连接收集层和处理层)。如下图所示:
图中箭头代表数据流向 – 从应用程序(左侧)流到终端存储设备(如果有的话,在右侧)。其中存储设备是可选的,因为日志处理的结果也许是执行一些动作而非把信息保存在某处。比如,您的程序运行处于危险状态,可以发出一个特殊的日志,在系统托盘区显示一个提示框并发出报警音, dang~。日志库有个非常重要的特点:收集数据、处理数据的过程和数据本身的组成是无关的。这个特点意味着库用户不但可以进行传统的记录日志,还可以给最终用户标记重要事件和积累统计数据。
Log Source
我们回到上面的图,左侧是您的应用程序发出的Log record,她们在logger的帮助下格式化数据并最终形成Logs。日志库提供许多不同类型的logger,而且你也可以自己构造logger来做扩展。Logger被设计成一系列独立特征的混合体,这些独立的特征可以任意组合。您可以简单开发些私有特征然后把她们倒进这锅汤里。构造好的logger可以嵌入应用程序类或者作为全局变量使用。这2种做法各有利弊。把logger嵌入某个类可以实现按类实例区分日志,从函数式编程的角度而言,全局变量的用法提供了更简单的访问途径。
总体来说,日志库对logger的用法不做要求,能写日志就行。更通俗一点词log source则定义了一个实体,这个实体构造出log record从而开启日志之旅。其他的log source也许还会包含从子应用中捕获的数据或者网络数据,但logger无疑是最常见的一种log source。
Attribute,Attribute value
要发起日志功能log source就要传输所有和log record相关的数据给logging core。这些数据或者更精确的说数据的捕获逻辑是以一系列我们称之为”attribute*的东西展现的。每一个attribute基本上都是一个函数,其返回值称为attribute value,这些attribute value才是下一阶段的处理对象。一个attribute的例子是返回当前时间的函数。她的返回值(具体的时间点)就是attribute value。
有3种类型的attribute集合:
- 全局型
- 线程特有型
源特有型
从上图中我们可以看出前2个集合是由logging core维护的,不需要由log source传递就能启动日志。全局型attribute会附加在所有创建的log record上。显然,所谓线程特有型attribute只会附加在注册她们的线程产生的log record上。源特有型attribute是有启动日志的源维护的,她们只会附加在由特定的源产生的log record上。
当一个源启动日志时,这3中类型的attribute集合产生的attribute value都会被获取。这些attribute value组成一个命名的单一集合,然后做进一步处理。您可以向集合里增加更多attribute value,这些attribute value只会附加在特定的log record上,不会和log source或logging core绑定。需要注意的是,相同名称的attribute是可以出现在多个attribute集合中的。有优先级来解决名字冲突:全局型attribute的优先级最低,源特有型的优先级最高,低优先级的attribute在名字冲突中时会被舍弃。
Logging core, Log filter
在attribute value组装完成后,logging core决定这个log record要不要交给sink做进一步处理。这个过程称之为filtering。有2层filtering可用:全局filtering在logging core中首先被使用,她们可用快速的移除无用的log record;sink特有filtering随后被使用,每个sink有自己的特有filtering。sink特有filtering可用把log record导向不同的sink。值得注意的是,此时已经知道log record来自哪个log source已经变得没有意义了,filtering操作只依赖附加在log record中的attribute value。
要注意,对于给定的log record,filtering操作只会做一次。显然只有filtering开始之前就附加在log record中的attribute value才会参与filtering。其他一些attribute value例如log record信息,是典型的在filtering之后才附加进log record的;这些attribute value是无法参与filtering,她们只会在log formatter和log sink中使用。
Log Sink, Log formatter
如果一个log record通过filtering到达至少一个log sink,这个log record就被认为是可消费的。如果log sink支持格式化输出,在这时日志消息的格式化过程就开始。格式化后的消息和她对应的attribute value一起传给接受了log record的log sink。注意,格式化过程是基于log sink执行的,所以不同的log sink可以自己定义的格式输出log record。
也许您已然发现上图中的log sink由2部分组成:前端和后端。这种划分是为了抽取log sink的通用功能到前端,例如filtering,log formatter和线程同步机制。log sink前端就提供这些库,用户通常不用再去实现她们了。而后端通常是扩展库功能之地。log sink的后端才是真正处理log record的。她们可以是存文件的log sink;她们可以是把log record发往其他处理节点的log sink;她们也可以是上文中提及的弹出提示工具条的log sink – 随你怎么叫吧。最常用的log sink后端在日志库里已经有所提供。
处理上述的主流功能外,日志库还提供了各种各样的辅助工具,比如attribute,formatter和filtering的支持,lambda表达式和一些库初始化的辅助类。在《详情描述》一章您会找到关于她们的描述。但是对于日志库的新手,我们还是推荐您从《指南》一章开始。
翻译:Lanser@youkuaiyun.com
声明:本文旨在技术交流,可以转载,但如果是商业用途请务必和原作者确认。本人保留追诉权利。