3 在程序中使用log4net
在开始对你的程序进行日志记录前,需要先启动log4net引擎。这意味着你需要先配置前面提到的三种组件。你可以用两种方法来设定配置:在单独的文件中设定配置或在代码中定义配置。
因为下面几种原因,推荐在一个单独的文件中定义配置:
|你不需要重新编译源代码就能改变配置;
|你可以在程序正运行的时候就改变配置。这一点在一些WEB程序和远程过程调用的程序中有时很重要;
考虑到第一种方法的重要性,我们先看看怎样在文件中设定配置信息。
3.1 定义配置文件
配置信息可以放在如下几种形式文件的一种中。
在程序的配置文件里,如AssemblyName.config 或web.config.
在你自己的文件里。文件名可以是任何你想要的名字,如AppName.exe.xyz等.
log4net框架会在相对于AppDomain.CurrentDomain.BaseDirectory 属性定义的目录路径下查找配置文件。框架在配置文件里要查找的唯一标识是<log4net>标签。一个完整的配置文件的例子如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration>
<configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net-net-1.0"
/>
</configSections> <log4net> <root> <level value="WARN" /> <appender-ref ref="LogFileAppender" /> <appender-ref ref="ConsoleAppender" /> </root> <logger name="testApp.Logging"> <level value="DEBUG"/> </logger> <appender name="LogFileAppender" type="log4net.Appender.FileAppender" > <param name="File" value="log-file.txt" /> <param name="AppendToFile" value="true" /> <layout type="log4net.Layout.PatternLayout"> <param name="Header" value="[Header]\r\n"/> <param name="Footer" value="[Footer]\r\n"/>
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="WARN" /> </filter> </appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" > <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" /> </layout> </appender> </log4net> </configuration>
你可以直接将上面的文本拷贝到任何程序中使用,但是最好还是能够理解配置文件是怎样构成的。 只有当你需要在应用程序配置文件中使用log4net配置时,才需要在<configSection>标签中加入<section>配置节点入口。对于其他的单独文件,只有<log4net>标签内的文本才是必需的,这些标签的顺序并不是固定的。下面我们依次讲解各个标签内文本的含义:
3.1.1 <root>
<root> <level value="WARN" /> <appender-ref ref="LogFileAppender" /> <appender-ref ref="ConsoleAppender" /> </root>
在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在<root>标签里,可以定义level级别值和Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过<appender-ref>标签定义日志对象使用的Appender对象。<appender-ref>声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设定<logger>标签的additivity属性为false而改变。
<logger name="testApp.Logging" additivity="false">
</logger>
Additivity的值缺省是true.
3.1.2 <Logger>
<logger name="testApp.Logging">
<level value="DEBUG"/>
</logger>
<logger> 元素预定义了一个具体日志对象的设置。然后通过调用LogManager.GetLogger(“testAPP.Logging”)函数,你可以检索具有该名字的日志。如果LogManager.GetLogger(…)打开的不是预定义的日志对象,则该日志对象会继承根日志对象的属性。知道了这一点,我们可以说,其实<logger>标签并不是必须的。
3.1.3 <appender>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender" > <param name="File" value="log-file.txt" /> <param name="AppendToFile" value="true" /> <layout type="log4net.Layout.PatternLayout"> <param name="Header" value="[Header]\r\n" /> <param name="Footer" value="[Footer]\r\n"/> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="WARN" /> </filter> </appender>
在<root>标签或单个的<logger>标签里的Appender对象可以用<appender>标签定义。<appender>标签的基本形式如上面所示。它定义了appender的名字和类型。 另外比较重要的是<appender>标签内部的其他标签。不同的appender有不同的<param>标签。在这里,为了使用FileAppender,你需要一个文件名作为参数。另外还需要一个在<appender>标签内部定义一个Layout对象。Layout对象定义在它自己的<layout>标签内。<layout>标签的type属性定义了Layout的类型(在本例里是PatternLayout),同时也确定了需要提供的参数值。Header和Footer标签提供了一个日志会话(logging session)开始和结束时输出的文字。有关每种appender的具体配置的例子,可以在log4net\doc\manual\example-config-appender.html中得到。
3.1.4 log4net.Layout.PatternLayout中的转换模式(ConversionPattern)
%m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
%n(new line):换行
%d(datetime):输出当前语句运行的时刻
%r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数
%t(thread id):当前语句所在的线程ID
%p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
%c(class):当前日志对象的名称
例如:
模式字符串为:%-10c -%m%n
代码为:
ILog log=LogManager.GetLogger(“Exam.Log”);
log.Debug(“Hello”);
则输出为下面的形式:
Exam.Log - Hello
%L:输出语句所在的行号
%F:输出语句所在的文件名
%-数字:表示该项的最小长度,如果不够,则用空格填充
例如,转换模式为%r [%t]%-5p %c - %m%n 的 PatternLayout 将生成类似于以下内容的输出:
176 [main] INFO org.foo.Bar - Located nearest gas station.
3.1.5 <filter>
最后,让我们看看在Appender元素里的<filter>标签。它定义了应用到Appender对象的过滤器。本例中,我们使用了LevelRangeFilter过滤器,它可以只记录LevelMin和LevelMax参数指定的日志级别之间的日志事件。可以在一个Appender上定义多个过滤器(Filter),这些过滤器将会按照它们定义的顺序对日志事件进行过滤。其他过滤器的有关信息可以在log4net的SDK文档中找到。
3.2 使用配置文件
3.2.1 关联配置文件
当我们创建了上面的配置文件后,我们接下来需要把它和我们的应用联系起来。缺省的,每个独立的可执行程序集都会定义它自己的配置。log4net框架使用 log4net.Config.DOMConfiguratorAttribute在程序集的级别上定义配置文件。
例如:可以在项目的AssemblyInfo.cs文件里添加以下的语句
[assembly:log4net.Config.DOMConfigurator(ConfigFile="filename",
ConfigFileExtension="ext",Watch=true/false)]
l Configfile:指出了我们的配置文件的路径及文件名,包括扩展名。
l ConfigFileExtension:如果我们对被编译程序的程序集使用了不同的文件扩展名,那么我们需要定义这个属性,缺省的,程序集的配置文件扩展名为”config”。
l Watch (Boolean属性): log4net框架用这个属性来确定是否需要在运行时监视文件的改变。如果这个属性为true,那么FileSystemWatcher将会被用来监视文件的改变,重命名,删除等事件。
其中:ConfigFile和ConfigFileExtension属性不能同时使用,ConfigFile指出了配置文件的名字,例如,ConfigFile=”Config.txt”
ConfigFileExtension则是指明了和可执行程序集同名的配置文件的扩展名,例如,应用程序的名称是”test.exe”,ConfigFileExtension=”txt”,则配置文件就应该是”test.exe.txt” ;
也可以不带参数应用DOMConfiguratio():
[assembly: log4net.Config.DOMConfigurator()]
也可以在程序代码中用DOMConfigurator类打开配置文件。类的构造函数需要一个FileInfo对象作参数,以指出要打开的配置文件名。 这个方法和前面在程序集里设置属性打开一个配置文件的效果是一样的。
log4net.Config.DOMConfigurator.Configure(
new FileInfo("TestLogger.Exe.Config"));
DOMConfigurator 类还有一个方法ConfigureAndWatch(..), 用来配置框架并检测文件的变化。
以上的步骤总结了和配置相关的各个方面,下面我们将分两步来使用logger对象。
3.2.2 创建或获取日志对象
日志对象会使用在配置文件里定义的属性。如果某个日志对象没有事先在配置文件里定义,那么框架会根据继承结构获取祖先节点的属性,最终的,会从根日志获取属性。如下所示:
Log4net.ILog log = Log4net.LogManager.GetLogger("MyLogger");
3.2.3 输出日志信息
可以使用ILog的几种方法输出日志信息。你也可以在调用某方法前先检查IsXXXEnabled布尔变量,再决定是否调用输出日志信息的函数,这样可以提高程序的性能。因为框架在调用如ILog.Debug(…)这样的函数时,也会先判断是否满足Level日志级别条件。
if (log.IsDebugEnabled) log.Debug("message");
if (log.IsInfoEnabled) log.Info("message);
3.3 在程序中配置log4net
除了前面讲的用一个配置文件来配置log4net以外,还可以在程序中用代码来配置log4net框架。如下面的例子:
// 和PatternLayout一起使用FileAppender log4net.Config.BasicConfigurator.Configure( new log4net.Appender.FileAppender( new log4net.Layout.PatternLayout("%d [%t]%-5p %c [%x] - %m%n"),"testfile.log")); // using a FileAppender with an XMLLayout log4net.Config.BasicConfigurator.Configure( new log4net.Appender.FileAppender( new log4net.Layout.XMLLayout(),"testfile.xml")); // using a ConsoleAppender with a PatternLayout log4net.Config.BasicConfigurator.Configure( new log4net.Appender.ConsoleAppender( new log4net.Layout.PatternLayout("%d [%t] %-5p %c - %m%n"))); // using a ConsoleAppender with a SimpleLayout log4net.Config.BasicConfigurator.Configure( new log4net.Appender.ConsoleAppender(new log4net.Layout.SimpleLayout()));
尽管这里用代码配置log4net也很方便,但是你却不能分别配置每个日志对象。所有的这些配置都是被应用到根日志上的。
log4net.Config.BasicConfigurator 类使用静态方法Configure 设置一个Appender 对象。而Appender的构造函数又会相应的要求Layout对象。你也可以不带参数直接调用BasicConfigurator.Configure(),它会使用一个缺省的PatternLayout对象,在一个ConsoleAppender中输出信息。如下所示:
log4net.Config.BasicConfigurator.Configure();
在输出时会显示如下格式的信息:
0 [1688] DEBUG log1 A B C - Test
20 [1688] INFO log1 A B C - Test
当log4net框架被配置好以后,就可以如前所述使用日志功能了。
4 总结
使用log4net可以很方便地为应用添加日志功能。应用Log4net,使用者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能。同时,通过外部配置文件,用户可以不用重新编译程序就能改变应用的日志行为,使得用户可以根据情况灵活地选择要记录的信息。