log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输出到不同的媒介。其大致分为如下这些模块。
Appenders模块
Appenders用来定义日志的输出方式,即日志要写到那种介质上去。较常用的Log4net已经实现好了,直接在配置文件中调用即可,可参见上面配置文件例子;当然也可以自己写一个,需要从log4net.Appender.AppenderSkeleton类继承。它还可以通过配置Filters和Layout来实现日志的过滤和输出格式。常用的有以下几种:
(1)AdoNetAppender 将日志记录到数据库中。可以采用SQL和存储过程两种方式。
(2)ConsoleAppender 将日志输出到应用程序控制台。
(3)EventLogAppender 将日志写到Windows Event Log。
(4)FileAppender 将日志输出到文件。
(5)SmtpAppender 将日志写到邮件中。
Filters模块
用过滤器可以过滤掉Appender输出的内容。过滤器通常有以下几种:
DenyAllFilter 阻止所有的日志事件被记录 。
LevelMatchFilter 只有指定等级的日志事件才被记录 。
LevelRangeFilter 日志等级在指定范围内的事件才被记录 。
LoggerMatchFilter 与Logger名称匹配,才记录 。
PropertyFilter 消息匹配指定的属性值时才被记录 。
StringMathFilter 消息匹配指定的字符串才被记录 。
Layouts模块
Layout用于控制Appender的输出格式,可以是线性的也可以是XML。
一个Appender只能有一个Layout。
最常用的Layout应该是经典格式的PatternLayout,其次是SimpleLayout,RawTimeStampLayout和ExceptionLayout。然后还有IRawLayout,XMLLayout等几个,使用较少。Layout可以自己实现,需要从log4net.Layout.LayoutSkeleton类继承,来输出一些特殊需要的格式,在后面扩展时就重新实现了一个Layout。
SimpleLayout简单输出格式,只输出日志级别与消息内容。
RawTimeStampLayout 用来格式化时间,在向数据库输出时会用到。
样式如“yyyy-MM-dd HH:mm:ss“
ExceptionLayout需要给Logger的方法传入Exception对象作为参数才起作用,否则就什么也不输出。输出的时候会包含Message和Trace。
PatterLayout使用最多的一个Layout,能输出的信息很多,使用方式可参见上面例子中的配置文件。PatterLayout的格式化字符串见文后附注。
Loggers模块
Logger是直接和应用程序交互的组件。Logger只是产生日志,然后由它引用的Appender记录到指定的媒介,并由Layout控制输出格式。
Logger提供了多种方式来记录一个日志消息,也可以有多个Logger同时存在。每个实例化的Logger对象对被log4net作为命名实体(Named Entity)来维护。log4net使用继承体系,也就是说假如存在两个Logger,名字分别为a.b.c和a.b。那么a.b就是a.b.c的祖先。每个Logger都继承了它祖先的属性。所有的Logger都从Root继承, Root本身也是一个Logger。
日志的等级,它们由高到底分别为:
OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL
高于等级设定值方法(如何设置参见“配置文件详解”)都能写入日志, Off所有的写入方法都不写到日志里,ALL则相反。例如当我们设成Info时,logger.Debug就会被忽略而不写入文件,但是FATAL, ERROR,WARN,INFO会被写入,因为他们等级高于INFO。
在具体写日志时,一般可以这样理解日志等级:
FATAL(致命错误):记录系统中出现的能使用系统完全失去功能,服务停止,系统崩溃等使系统无法继续运行下去的错误。例如,数据库无法连接,系统出现死循环。
ERROR(一般错误):记录系统中出现的导致系统不稳定,部分功能出现混乱或部分功能失效一类的错误。例如,数据字段为空,数据操作不可完成,操作出现异常等。
WARN(警告):记录系统中不影响系统继续运行,但不符合系统运行正常条件,有可能引起系统错误的信息。例如,记录内容为空,数据内容不正确等。
INFO(一般信息):记录系统运行中应该让用户知道的基本信息。例如,服务开始运行,功能已经开户等。
DEBUG (调试信息):记录系统用于调试的一切信息,内容或者是一些关键数据内容的输出。
Logger实现的ILog接口,ILog定义了5个方法(Debug,Inof,Warn,Error,Fatal)分别对不同的日志等级记录日志。这5个方法还有5个重载。以Debug为例说明一下,其它的和它差不多。
ILog中对Debug方法的定义如下:
void Debug(object message);
void Debug(object message, Exception ex);
还有一个布尔属性:
bool IsDebugEnabled { get; }
如果使用Debug(object message, Exception ex),则无论Layout中是否定义了%exception,默认配置下日志都会输出Exception。包括Exception的Message和Trace。如果使用Debug(object message),则日志是不会输出Exception。
最后还要说一个LogManager类,它用来管理所有的Logger。它的GetLogger静态方法,可以获得配置文件中相应的Logger:
log4net.ILog log = log4net.LogManager.GetLogger("logger-name");
Object Renders模块
它将告诉logger如何把一个对象转化为一个字符串记录到日志里。(ILog中定义的接口接收的参数是Object,而不是String。)
例如你想把Orange对象记录到日志中,但此时logger只会调用Orange默认的ToString方法而已。所以要定义一个OrangeRender类实现log4net.ObjectRender.IObjectRender接口,然后注册它(我们在本文中的扩展不使用这种方法,而是直接实现一个自定义的Layout)。这时logger就会知道如何把Orange记录到日志中了。
Repository模块
Repository主要用于负责日志对象组织结构的维护。在log4net的以前版本中,框架仅支持分等级的组织结构(hierarchical organization)。这种等级结构本质上是库的一个实现,并且定义在log4net.Repository.Hierarchy 名字空间中。要实现一个Repository,需要实现log4net.Repository.ILoggerRepository 接口。但是通常并不是直接实现该接口,而是以log4net.Repository.LoggerRepositorySkeleton为基类继承。体系库(hierarchical repository )则由log4net.Repository.Hierarchy.Hierarchy类实现。
如果你是个log4net框架的使用者,而非扩展者,那么你几乎不会在你的代码里用到Repository的类。相反的,你需要用到LogManager类来自动管理库和日志对象。
总结
上面的结构我们可以把log4net当成一个“人”,然后上面的部分都是她的四肢或者其他部分等等。既然知道这个人的四肢和特点了,那么如何让这个人干她该干的活?下一篇文章中我进行介绍。