1 介绍
log4net(log for net)是apache 开源的应用于.net框架的日志记录工具,详细信息参见apache 网站.它是针对java的log4j(log for java的)姊妹工具.用过log4j的都知道,它功能强大,可配置性灵活,线程安全,对日志的输出管理和级别管理方便。具体的使用方法往下看。
首先你应该下载log4net.dll并引入到你的项目references中,或者把源代码项目作为你工程的一部分加入到你的工程当中。单击这里下载log4net 。
使用log4net需要知道其中两个比较重要的概念:logger 和 appender。前者是日志记录对象,后者是日志记录的目标,包括控制台,文件,定量大小的文件,远程广播。也就是说我们使用log4net的过程可以 是这样的:获得一个用来记录日志的工具对象logger,然后为logger对象指定日志的记录位置.美妙的是,这一切工作都可以在web.config 配置文件中完成,所用的代码极少。
1.1 优点
几乎所有的大型应用都会有自己的用于跟踪调试的api。因为一旦程序被部署以后,就不太可能再利用专门的调试工具了。然而一个管理员可能需要有一套强大的日志系统来诊断和修复配置上的问题。
经验表明,日志记录往往是软件开发周期中的重要组成部分。它具有以下几个优点:它可以提供应用程序运行时的精确环境,可供开发人员尽快找到应用程序 中的bug;一旦在程序中加入了log 输出代码,程序运行过程中就能生成并输出日志信息而无需人工干预。另外,日志信息可以输出到不同的地方(控制台,文件等)以备以后研究之用。
log4net就是为这样一个目的设计的,用于.net开发环境的日志记录包。
1.2安装
用户要在自己的程序里加入日志功能,只需将log4net.dll引入工程即可。
1.3结构
log4net 有四种主要的组件,分别是logger(记录器), repository(库), appender(附着器)以及 layout(布局)。
1.4logger接口
logger是应用程序需要交互的主要组件,它用来产生日志消息。产生的日志消息并不直接显示,还要预先经过layout的格式化处理后才会输出。
logger 提供了多种方式来记录一个日志消息,你可以在你的应用程序里创建多个logger,每个实例化的logger对象都被log4net框架作为命名实体 (named entity)来维护。这意味着为了重用logger对象,你不必将它在不同的类或对象间传递,只需要用它的名字为参数调用就可以了。log4net框架 使用继承体系,继承体系类似于.net中的名字空间。也就是说,如果有两个logger,分别被定义为a.b.c和a.b,那么我们说a.b是a.b.c 的祖先。每一个logger都继承了祖先的属性
log4net框架定义了一个ilog接口,所有的logger类都必须实现这个接口。如果你想实现一个自定义的logger,你必须首先实现这个接口。你可以参考在/extension目录下的几个例子。
ilog接口的定义如下:
public interface ilog
{
void debug(object message);
void info(object message);
void warn(object message);
void error(object message);
void fatal(object message);
//以上的每一个方法都有一个重载的方法,用来支持异常处理。
//每一个重载方法都如下所示,有一个异常类型的附加参数。
void debug(object message, exception ex);
// ...
//boolean 属性用来检查logger的日志级别
//(我们马上会在后面看到日志级别)
bool isdebugenabled;
bool isinfoenabled;
//… 其他方法对应的boolean属性
}
log4net框架定义了一个叫做logmanager的类,用来管理所有的logger对象。它有一个getlogger()静态方法,用我们提 供的名字参数来检索已经存在的logger对象。如果框架里不存在该logger对象,它也会为我们创建一个logger对象。代码如下所示:
log4net.ilog log = log4net.logmanager.getlogger("logger-name");
通常来说,我们会以类(class)的类型(type)为参数来调用getlogger(),以便跟踪我们正在进行日志记录的类。传递的类(class)的类型(type)可以用typeof(classname)方法来获得,或者可以用如下的反射方法来获得:
system.reflection.methodbase.getcurrentmethod().declaringtype
尽管符号长了一些,但是后者可以用于一些场合,比如获取调用方法的类(class)的类型(type)。
正如你在ilog的接口中看到的一样,有五种不同的方法可以跟踪一个应用程序。事实上,这五种方法是运作在logger对象设置的不同日志优先级别 上。这几种不同的级别是作为常量定义在log4net.spi.level类中。你可以在程序中使用任何一种方法。但是在最后的发布中你也许不想让所有的 代码来浪费你的cpu周期,因此,框架提供了7种级别和相应的boolean属性来控制日志记录的类型。
level有以下几种取值
级别 | 允许的方法 | boolean属性 | 优先级别 |
off |
|
| highest |
fatal | void fatal(...); | bool isfatalenabled; |
|
rror | void error(...); | bool iserrorenabled; |
|
warn | void warn(...); | bool iswarnenabled; |
|
info | void info(...); | bool isinfoenabled; |
|
debug | void debug(...); | bool isdebugenabled; |
|
all |
|
| lowest |
在log4net框架里,通过设置配置文件,每个日志对象都被分配了一个日志优先级别。如果没有给一个日志对象显式地分配一个级别,那么该对象会试图从他的祖先继承一个级别值。
ilog接口的每个方法都有一个预先定义好了的级别值。正如你在表1看到的,ilog的inof()方法具有info级别。同样的,以此类 推,error()方法具有error级别。当我们使用以上的任何一种方法时,log4net框架会检查日志对象logger的级别和方法的级别。只有当 方法的级别高于日志级别时,日志请求才会被接受并执行。
举例说明,当你创建了一个日志对象,并且把他的级别设置为info。于是框架会设置日志的每个boolean属性。当你调用相应的日志方法时,框架会检查相应的boolean属性,以决定该方法能不能执行。如下的代码:
logger.info("message");
logger.debug("message");
logger.warn("message");
对于第一种方法,info()的级别等与日志的级别(info),因此日志请求会被传递,我们可以得到输出结果”message”。
对于第二种方法,debug()的级别低于日志对象logger的日志级别(info),因此,日志请求被拒绝了,我们得不到任何输出。同样的,针对第三行语句,我们可以很容易得出结论。
在表1中有两个特殊的级别:all和off。all表示允许所有的日志请求。off是拒绝所有的请求。
你也可以显式地检查logger对象的boolean属性,如下所示:
if (logger.isdebugenabled)
{
logger.debug("message");
}
1.5repository接口
repository主要用于负责日志对象组织结构的维护。在log4net的以前版本中,框架仅支持分等级的组织结构(hierarchical organization)。这种等级结构本质上是库的一个实现,并且定义在log4net.repository.hierarchy 名字空间中。要实现一个repository,需要实现log4net.repository.iloggerrepository 接口。但是通常并不是直接实现该接口,而是以log4net.repository.loggerrepositoryskeleton为基类继承。体系 库 (hierarchical repository )则由log4net.repository.hierarchy.hierarchy类实现。
如果你是个log4net框架的使用者,而非扩展者,那么你几乎不会在你的代码里用到repository的类。相反的,你需要用到logmanager类来自动管理库和日志对
1.6appender
一个好的日志框架应该能够产生多目的地的输出。比如说输出到控制台或保存到一个日志文件。log4net 能够很好的满足这些要求。它使用一个叫做appender的组件来定义输出介质。正如名字所示,这些组件把它们附加到logger日志组件上并将输出传递 到输出流中。你可以把多个appender组件附加到一个日志对象上。 log4net框架提供了几个appender组件。关于log4net提供的appender组件的完整列表可以在log4net框架的帮助手册中找 到。有了这些现成的appender组件,一般来说你没有必要再自己编写了。但是如果你愿意,可以从 log4net.appender.appenderskeleton类继承。
2 配置说明
先在web.config中的<configuration>节点下添加如下配置:
<configsections>
<section name="log4net" type="log4net.config.log4netconfigurationsectionhandler, log4net" />
</configsections>
还应该配置log4net节点,接下来在<configuration>节点下添加如下log4net节点配置:
<log4net>
<root>
<level value=" debug" />
<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="c://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>
从上面的配置中可以看到定义了多个appender,每一个appender就是一个日志记录的目标。root节点指定了选用哪一个 appender. 在这里我选用了logfileappender。到这里配置就基本上完成了,但是怎么使用上面的配置呢?log4net为我们提供了在应用程序启动时加载 配置信息的入口,很简单,在global.asax.cs的application_start过程中添加如下代码:
log4net.config.domconfigurator.configure();
好了,到此为止整个配置过程完成了,下面是怎么调用的问题了
1、 关联配置文件
当我们创建了上面的配置文件后,我们接下来需要把它和我们的应用联系起来。缺省的,每个独立的可执行程序集都会定义它自己的配置。log4net框架使用 log4net.config.domconfiguratorattribute在程序集的级别上定义配置文件。
例如:可以在项目的assemblyinfo.cs文件里添加以下的语句
[assembly:log4net.config.domconfigurator(configfile="filename",
configfileextension="ext",watch=true/false)]
configfile:指出了我们的配置文件的路径及文件名,包括扩展名。
configfileextension:如果我们对被编译程序的程序集使用了不同的文件扩展名,那么我们需要定义这个属性,缺省的,程序集的配置文件扩展名为”config”。
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对象。
2 、创建或获取日志对象
日志对象会使用在配置文件里定义的属性。如果某个日志对象没有事先在配置文件里定义,那么框架会根据继承结构获取祖先节点的属性,最终的,会从根日 志获取属性。如下所示: log4net.ilog log = log4net.logmanager.getlogger("mylogger");
3、 输出日志信息
可以使用ilog的几种方法输出日志信息。你也可以在调用某方法前先检查isxxxenabled布尔变量,再决定是否调用输出日志信息的函数,这 样可以提高程序的性能。因为框架在调用如ilog.debug(…)这样的函数时,也会先判断是否满足level日志级别条件。
if (log.isdebugenabled) log.debug("message");
if (log.isinfoenabled) log.info("message);
4、 在程序中配置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框架被配置好以后,就可以如前所述使用日志功能了。
3 调用
新建一个log4nettest.aspx页面,在cs文件中添加引用 using log4net;定义本页的一个全局变量:private static readonly ilog log = logmanager.getlogger(typeof(log4nettest));
然后在page_load中添加如下代码:log.debug("这是我在使用log4net");运行该页面,在c:/下面会生成一个c://log-file.tx文本文件,打开看看,里面就有你写入的日志。
在global.asax添加如下的内容:
void application_start(object sender, eventargs e)
{
// code that runs on application startup
log4net.config.domconfigurator.configure();
}