转载:http://blog.csdn.net/shanno/article/details/7442647
纪念下我曾经的一句名言:需求是软件开发的根本准则。
Logging architecture
需求一:记录需要包含的内容?消息的内容、消息生成的时间和地点、消息的重要性。
这些东西都有Message对象来描述。一条记录就是一个Message对象。Message对象非常像一个装饰模式,Text是Message的内容,Message中的其它属性是对Text的装饰(或者用描述更确切点):
Priority——消息的优先级
Source——生成消息的地方
Timestamp——生成消息的时间
Process&threadidentifier——生成消息的进程ID和线程ID
OptionalParameter (name value pair )——附加参数,主要用于格式化消息
需求二:当拥有了大量的消息之后,如何高效的管理这些消息?比如,根据消息的优先级过滤掉某些较低优先级的消息,或者快速地找到生成消息的地方等。
Logger类负责记录消息,并且根据自身的level,可以忽略一些不是很重要的消息。一个Logger只记录一个地点上生成的消息,比如,一个Logger记录一个类上生成的消息。我们都知道类是有继承结构的,为了更好地配合这种结构,Poco给我们提供了一个Logger工厂方法get()来创建Logger。由它创建的Logger,可以很容易地生成另外一个继承层次,如下图
创建这个继承结构,Logger::get()方法为用户做了大部分工作。使用者只需要制定合理的Logger名字,Logger::get()方法就能为我们生成这个结构。通过一个句点(.),来分离父亲和孩子,左边是父亲右边是孩子。比如,HTTPServer和HTTPServer.Listener。这样,HTTPServer.Listener就具有了与其父亲HTTPServer相同的配置。这个配置主要是后面会讲到的Channel。
需求三:由Logger记录的消息该输出到什么地方?标准输出?文件?还是应用程序的某个窗口上?或者是。。。
这部分工作是由Channel来完成的。Channel的接口非常简单,只有一个log()。Log方法负责将消息输出到消息该去的地方。Poco提供了很多现成的Channel,比如ConsoleChannel(默认将消息输出到std::clog,也可以将其输出到std::out),FileChannel将消息输出到一个文件中。
需求四:如何格式化输出消息?比如,仅仅输出消息的内容,还是需要输出消息的其它附加内容,比如timestamp、process id 等。
原理就是在由Channel输出消息之前,让消息先通过Formater格式化后再通过Channel输出。FormattingChannel类的作用有点类似proxy模式,它一方面调用了Channel的方法,不过在调用Channel的方法之前,先让消息流过Formatter了。
上面程序的输出结果:在文件sample.log中的内容为:
00:19:52:359 LoggerTest(4): This is a warning.
00:19:52:390 LoggerTest(3): This is a error