声明:本文内容主要来自网络,亦加入了个人的一点心得。
一、简介
1、Log4net的优点:
几乎所有的大型应用都会有自己的用于跟踪调试的API。因为一旦程序被部署以后,就不太可能再利用专门的调试工具了。然而一个管理员可能需要有一套强大的日志系统来诊断和修复配置上的问题。
经验表明,日志记录往往是软件开发周期中的重要组成部分。它具有以下几个优点:它可以提供应用程序运行时的精确环境,可供开发人员尽快找到应用程序中的Bug;一旦在程序中加入了Log 输出代码,程序运行过程中就能生成并输出日志信息而无需人工干预。另外,日志信息可以输出到不同的地方(控制台,文件等)以备以后研究之用。
Log4net就是为这样一个目的设计的,用于.NET开发环境的日志记录包。
2、Log4net的获取:
用户可以从http://logging.apache.org/log4net/download_log4net.cgi下载log4net的动态库。解压软件包后,打开目录得到如下目录结构:
打开bin目录:
打开net目录,选择针对.NET FramerWork的不同版本:
找到相应版本的log4net.dll
二、Log4net的结构
log4net 有四种主要的组件,分别是Logger(记录器), Repository(库), Appender(附着器)以及 Layout(布局)。
2.1 Logger
2.1.1 Logger接口
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类都必须实现这个接口。下面是本人对这个接口的实现:
1 using System; 2 using log4net; 3 namespace ActionHelper 4 { 5 public class LogHelper 6 { 7 private ILog logger; 8 public LogHelper(ILog log) 9 { 10 this.logger = log; 11 } 12 public void Info(object message) 13 { 14 this.logger.Info(message); 15 } 16 public void Info(object message, Exception e) 17 { 18 this.logger.Info(message, e); 19 } 20 public void Debug(object message) 21 { 22 this.logger.Debug(message); 23 } 24 public void Debug(object message, Exception e) 25 { 26 this.logger.Debug(message, e); 27 } 28 public void Warming(object message) 29 { 30 this.logger.Warn(message); 31 } 32 public void Warming(object message, Exception e) 33 { 34 this.logger.Warn(message, e); 35 } 36 public void Error(object message) 37 { 38 this.logger.Error(message); 39 } 40 public void Error(object message, Exception e) 41 { 42 this.logger.Error(message, e); 43 } 44 public void Fatal(object message) 45 { 46 this.logger.Fatal(message); 47 } 48 public void Fatal(object message, Exception e) 49 { 50 this.logger.Fatal(message, e); 51 } 52 } 53 public class LogFactory 54 { 55 static LogFactory() 56 { 57 } 58 public static LogHelper GetLogger(Type type) 59 { 60 return new LogHelper(LogManager.GetLogger(type)); 61 } 62 public static LogHelper GetLogger(string str) 63 { 64 return new LogHelper(LogManager.GetLogger(str)); 65 } 66 } 67 } View CodeLog4net框架定义了一个叫做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)。
2.1.2 日志的级别
正如你在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接口的每个方法都有一个预先定义好了的级别值,ILog的Inof()方法具有INFO级别。同样的,以此类推,Error()方法具有ERROR级别。当我们使用以上的任何一种方法时,log4net框架会检查日志对象logger的级别和方法的级别。只有当方法的级别高于日志级别时,日志请求才会被接受并执行。
2.2 Repository
Repository主要用于负责日志对象组织结构的维护。在log4net的以前版本中,框架仅支持分等级的组织结构(hierarchical organization)。这种等级结构本质上是库的一个实现,并且定义在log4net.Repository.Hierarchy 名字空间中。要实现一个Repository,需要实现log4net.Repository.ILoggerRepository 接口。但是通常并不是直接实现该接口,而是以log4net.Repository.LoggerRepositorySkeleton为基类继承。体系库 (hierarchical repository )则由log4net.Repository.Hierarchy.Hierarchy类实现。
如果你是个log4net框架的使用者,而非扩展者,那么你几乎不会在你的代码里用到Repository的类。相反的,你需要用到LogManager类来自动管理库和日志对象。
2.3 Appender
一个好的日志框架应该能够产生多目的地的输出。比如说输出到控制台或保存到一个日志文件。log4net 能够很好的满足这些要求。它使用一个叫做Appender的组件来定义输出介质。正如名字所示,这些组件把它们附加到Logger日志组件上并将输出传递到输出流中。你可以把多个Appender组件附加到一个日志对象上。 Log4net框架提供了几个Appender组件。关于log4net提供的Appender组件的完整列表可以在log4net框架的帮助手册中找到。有了这些现成的Appender组件,一般来说你没有必要再自己编写了。但是如果你愿意,可以从log4net.Appender.AppenderSkeleton类继承。
2.4 Appender Filters
一个Appender 对象缺省地将所有的日志事件传递到输出流。Appender的过滤器(Appender Filters) 可以按照不同的标准过滤日志事件。在log4net.Filter的名字空间下已经有几个预定义的过滤器。使用这些过滤器,你可以按照日志级别范围过滤日志事件,或者按照某个特殊的字符串进行过滤。你可以在API的帮助文件中发现更多关于过滤器的信息。
2.5 Layout
Layout 组件用于向用户显示最后经过格式化的输出信息。输出信息可以以多种格式显示,主要依赖于我们采用的Layout组件类型。可以是线性的或一个XML文件。Layout组件和一个Appender组件一起工作。API帮助手册中有关于不同Layout组件的列表。一个Appender对象,只能对应一个Layout对象。要实现你自己的Layout类,你需要从log4net.Layout.LayoutSkeleton类继承,它实现了ILayout接口。
三、在程序中使用log4net
在开始对你的程序进行日志记录前,需要先启动log4net引擎。这意味着你需要先配置前面提到的三种组件。你可以用两种方法来设定配置:在单独的文件中设定配置或在代码中定义配置。
因为下面几种原因,推荐在一个单独的文件中定义配置:
你不需要重新编译源代码就能改变配置;
你可以在程序正运行的时候就改变配置。这一点在一些WEB程序和远程过程调用的程序中有时很重要;
考虑到第一种方法的重要性,我们先看看怎样在文件中设定配置信息。
3.1 定义配置文件
配置信息可以放在如下几种形式文件的一种中。
在程序的配置文件里,如AssemblyName.config 或web.config.
在你自己的文件里。文件名可以是任何你想要的名字,如log4net.xml等.
log4net框架会在相对于AppDomain.CurrentDomain.BaseDirectory 属性定义的目录路径下查找配置文件。框架在配置文件里要查找的唯一标识是<log4net>标签。
一个完整的配置文件的例子如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 3 <configuration> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> 6 </configSections> 7 8 <log4net> 9 <logger name="testApp.Logging"> 10 <level value="DEBUG"/> 11 </logger> 12 13 <root> 14 <level value="all" /> 15 <appender-ref ref="INFOAppender" /> 16 <appender-ref ref="DEBUGAppender" /> 17 <appender-ref ref="WARNAppender" /> 18 <appender-ref ref="ERRORAppender" /> 19 <appender-ref ref="FATALAppender" /> 20 <appender-ref ref="ColoredConsole" /> 21 <appender-ref ref="TraceAppender" /> 22 </root> 23 24 <appender name="INFOAppender" type="log4net.Appender.RollingFileAppender"> 25 <file value="logs\\INFO\\" /> 26 <appendToFile value="true" /> 27 <rollingStyle value="Composite" /> 28 <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.log'" /> 29 <staticLogFileName value="false"/> 30 <maxSizeRollBackups value="100" /> 31 <maximumFileSize value="10MB" /> 32 <layout type="log4net.Layout.PatternLayout"> 33 <conversionPattern value="