Log4Net使用详解(续)

http://zhoufoxcn.blog.51cto.com/792419/429988

明自从上次在2008年在博客上发表过有关log4net的用法介绍文章之后(网址:http://blog.csdn.net/zhoufoxcn/archive/2008/03/26/2220533.aspx),有不少朋友在博文下留言询问一些细节,现在就一些比较普遍的问题做一些稍微深入的解答,希望大家满意。

首先说明一点的是,log4net解决的问题是提供一个记录日志的框架,它提供了向多种目标写入的实现,比如利用log4net可以方便地将日 志信息记录到文件、控制台、Windows事件日志和数据库(包括MS SQL Server, Access, Oracle9i,Oracle8i,DB2,SQLite)中,一般来说我们只需要提供一个描述性的字符串,然后log4net就会自动提供有关运行时 的一些信息。
Log4Net的版本仍是1.2.10(2008年我写博文的时候也是这个版本),有.NET1.0和.NET1.1和.NET2.0版本,如果有正在使用高于.NET2.0开发的也不用担心,可以直接引用这个类库,像在.NET2.0中开发一样,它的网址是:http://logging.apache.org/log4net/
关于在Web中支持的问题
在我们开发项目时都会使用到config文件,可以在config文件中配置log4net。这一点Web项目和WinForm项目都是一样 的。需要注意的是,因为在Web项目中一般以较低权限的角色来运行Web项目的,所以在使用文件型日志时要注意不要放在本项目根文件夹之外。
在config文件中的配置
要使用log4net,首先要在config文件的<configSections>节点中增加配置(如果没有这个节点请手动增加),如下:
 
  1. <configSections> 
  2.   <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/> 
  3. </configSections> 
除此之外,还要在顶级节点<configuration>下增加<log4net>子节点。 在<log4net>节点下就可以增加<appender>子节点,每个<appender>子节点代表一种记录日 志的方式(仅在这里配置了不代表启用了)。
具体说来有如下Appender:
AdoNetAppender:利用ADO.NET记录到数据库的日志。
AnsiColorTerminalAppender:在ANSI 窗口终端写下高亮度的日志事件。
AspNetTraceAppender:能用asp.net中Trace的方式查看记录的日志。
BufferingForwardingAppender:在输出到子Appenders之前先缓存日志事件。
ConsoleAppender:将日志输出到控制台。
EventLogAppender:将日志写到Windows Event Log.
FileAppender:将日志写到文件中。
LocalSyslogAppender:将日志写到local syslog service (仅用于UNIX环境下).
MemoryAppender:将日志存到内存缓冲区。
NetSendAppender:将日志输出到Windows Messenger service.这些日志信息将在用户终端的对话框中显示。
RemoteSyslogAppender:通过UDP网络协议将日志写到Remote syslog service。
RemotingAppender:通过.NET Remoting将日志写到远程接收端。
RollingFileAppender:将日志以回滚文件的形式写到文件中。
SmtpAppender:将日志写到邮件中。
TraceAppender:将日志写到.NET trace 系统。
UdpAppender:将日志connectionless UDP datagrams的形式送到远程宿主或以UdpClient的形式广播。
关于使用log4net中可能会使用到的一些参数
%m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
%n(new line):换行
%d(datetime):输出当前语句运行的时刻
%r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数
%t(thread id):当前语句所在的线程ID
%p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
%c(class):当前日志对象的名称,例如:
%f(file):输出语句所在的文件名。
%l(line):输出语句所在的行号。
%数字:表示该项的最小长度,如果不够,则用空格填充,如“%-5level”表示level的最小宽度是5个字符,如果实际长度不够5个字符则以空格填充。
下面以一个实际的例子来说明问题,比如在配置中有“%date [%thread] (%file:%line) %-5level %logger [%property{NDC}] - %message%newline”,那么实际的日志中会是如下格式:
“记录时间:2010-11-17 16:16:36,561 线程ID:[9] 日志级别:文件:所在行ERROR 出错类:Log4NetDemo.Program property:[(null)] - 错误描述:error
System.Exception: 在这里发生了一个异常,Error Number:2036084948”
关于对数据库的支持
前面已经说过,log4net是支持包括MS SQL Server, Access, Oracle9i,Oracle8i,DB2,SQLite在内的数据库的,如果是文件型数据库(如Access或SQLite)的话就需要指定数据库文 件的位置(在Web中最好指定在有读写权限的文件夹下,并且实现创建好表),如果是网络数据库就需要指定正确的数据库连接字符串。
比如要记录到Oracle数据库中,在配置文件中可以增加一个< appender>节点,配置如下:
 
  1. <appender name="AdoNetAppender_Oracle" type="log4net.Appender.AdoNetAppender"> 
  2.       <connectionType value="System.Data.OracleClient.OracleConnection, System.Data.OracleClient" /> 
  3.       <connectionString value="data source=[mydatabase];User ID=[user];Password=[password]" /> 
  4.       <commandText value="INSERT INTO Log (Datetime,Thread,Log_Level,Logger,Message) VALUES (:log_date, :thread, :log_level, :logger, :message)" /> 
  5.       <bufferSize value="128" /> 
  6.       <parameter> 
  7.         <parameterName value=":log_date" /> 
  8.         <dbType value="DateTime" /> 
  9.         <layout type="log4net.Layout.RawTimeStampLayout" /> 
  10.       </parameter> 
  11.       <parameter> 
  12.         <parameterName value=":thread" /> 
  13.         <dbType value="String" /> 
  14.         <size value="255" /> 
  15.         <layout type="log4net.Layout.PatternLayout"> 
  16.           <conversionPattern value="%thread" /> 
  17.         </layout> 
  18.       </parameter> 
  19.       <parameter> 
  20.         <parameterName value=":log_level" /> 
  21.         <dbType value="String" /> 
  22.         <size value="50" /> 
  23.         <layout type="log4net.Layout.PatternLayout"> 
  24.           <conversionPattern value="%level" /> 
  25.         </layout> 
  26.       </parameter> 
  27.       <parameter> 
  28.         <parameterName value=":logger" /> 
  29.         <dbType value="String" /> 
  30.         <size value="255" /> 
  31.         <layout type="log4net.Layout.PatternLayout"> 
  32.           <conversionPattern value="%logger" /> 
  33.         </layout> 
  34.       </parameter> 
  35.       <parameter> 
  36.         <parameterName value=":message" /> 
  37.         <dbType value="String" /> 
  38.         <size value="4000" /> 
  39.         <layout type="log4net.Layout.PatternLayout"> 
  40.           <conversionPattern value="%message" /> 
  41.         </layout> 
  42.       </parameter> 
  43.     </appender> 
当然从上面的配置中的SQL语句中可以看得出这个表的参数,日志表的创建语句如下:
 
  1. create table log (  
  2.    Datetime timestamp(3),  
  3.    Thread varchar2(255),  
  4.    Log_Level varchar2(255),  
  5.    Logger varchar2(255),  
  6.    Message varchar2(4000)  
  7.    ); 
 

在本例中周公采用了将日志记录到SQLite这个单机数据库的方式,并且还将记录记录日志时的文件名和行号,创建SQLite的SQL语句如下:

 

  1. CREATE TABLE Log (  
  2.     LogId        INTEGER PRIMARY KEY,  
  3.     Date        DATETIME NOT NULL,  
  4.     Level        VARCHAR(50) NOT NULL,  
  5.     Logger        VARCHAR(255) NOT NULL,  
  6.     Source        VARCHAR(255) NOT NULL,  
  7.     Message        TEXT DEFAULT NULL 
  8.     ); 

增加的< appender>节点配置如下:

 

  1. <appender name="AdoNetAppender_SQLite" type="log4net.Appender.AdoNetAppender"> 
  2.   <bufferSize value="100" /> 
  3.   <connectionType value="System.Data.SQLite.SQLiteConnection, System.Data.SQLite, Version=1.0.66.0, Culture=neutral" /> 
  4.   <!--SQLite连接字符串--> 
  5.   <connectionString value="Data Source=c:\\log4net.db;Version=3;" /> 
  6.   <commandText value="INSERT INTO Log (Date, Level, Logger,Source, Message) VALUES (@Date, @Level, @Logger, @Source, @Message)" /> 
  7.   <parameter> 
  8.     <parameterName value="@Date" /> 
  9.     <dbType value="DateTime" /> 
  10.     <layout type="log4net.Layout.RawTimeStampLayout" /> 
  11.   </parameter> 
  12.   <parameter> 
  13.     <parameterName value="@Level" /> 
  14.     <dbType value="String" /> 
  15.     <layout type="log4net.Layout.PatternLayout"> 
  16.       <conversionPattern value="%level" /> 
  17.     </layout> 
  18.   </parameter> 
  19.   <parameter> 
  20.     <parameterName value="@Logger" /> 
  21.     <dbType value="String" /> 
  22.     <layout type="log4net.Layout.PatternLayout"> 
  23.       <conversionPattern value="%logger" /> 
  24.     </layout> 
  25.   </parameter> 
  26.   <parameter> 
  27.     <parameterName value="@Source" /> 
  28.     <dbType value="String" /> 
  29.     <layout type="log4net.Layout.PatternLayout"> 
  30.       <conversionPattern value="%file:%line" /> 
  31.     </layout> 
  32.   </parameter> 
  33.   <parameter> 
  34.     <parameterName value="@Message" /> 
  35.     <dbType value="String" /> 
  36.     <layout type="log4net.Layout.PatternLayout"> 
  37.       <conversionPattern value="%message" /> 
  38.     </layout> 
  39.   </parameter> 
  40. </appender> 
从上面的配置中可以看出插入数据的SQL语句及参数信息,下面的<parameter>节点就是指定插入的数据,比如我们指定 SQL语句中的"@Source"参数来源于log4net中的"%file:%line"参数,也就是这两个参数用“:”用连接起来。
控制日志文件大小的问题
对于一个长时间使用并且有大量业务日志的系统来说,如果使用FileAppender将日志一直记录到一个文件中会引起性能低下的问题,我曾见 过有个系统的日志文件达到了800多M,最后系统无法及时响应了,在这种情况下可考虑使用RollingFileAppender循环记录日志,一种是指 定文件的最大长度,如果超过了就重新生成一个文件,如下面的配置:
 
  1. <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 
  2.   <file value="RollingFileAppender_log.txt" /> 
  3.   <appendToFile value="true" /> 
  4.   <rollingStyle value="Size" /> 
  5.   <maxSizeRollBackups value="10" /> 
  6.   <maximumFileSize value="100KB" /> 
  7.   <staticLogFileName value="true" /> 
  8.   <layout type="log4net.Layout.PatternLayout"> 
  9.     <conversionPattern value="%date [%thread] (%file:%line) %-5level %logger [%property{NDC}] - %message%newline" /> 
  10.   </layout> 
  11. </appender> 
在上面的配置中,每个日志文件最大100KB,最大日志文件个数是10生成的日志文件名会是 RollingFileAppender_log.txt.1, RollingFileAppender_log.txt.2 ... RollingFileAppender_log.txt.10,如果记录的日志超过10个,会从 RollingFileAppender_log.txt.1开始覆盖。
还有一种方式就是按照日期记录日志,它的配置如下:
 
  1. <appender name="RollingLogFileAppender_DateFormat" type="log4net.Appender.RollingFileAppender"> 
  2.   <file value="RollingLogFileAppender_DateFormat_log.txt" /> 
  3.   <appendToFile value="true" /> 
  4.   <rollingStyle value="Date" /> 
  5.   <!--<datePattern value="yyyyMMdd-HHmm" />--> 
  6.   <datePattern value="yyyyMMdd" /> 
  7.   <layout type="log4net.Layout.PatternLayout"> 
  8.     <conversionPattern value="%date [%thread](%file:%line) %-5level %logger [%property{NDC}] - %message%newline" /> 
  9.   </layout> 
  10. </appender> 
这样一来,每天的日志都写入到一个文件中,当天的日志文件名为 “RollingLogFileAppender_DateFormat_log.txt”,非当天的日志都会带上当天的日期,如 “RollingLogFileAppender_DateFormat_log.txt20101117”表示2010年11月17日的日志,这样就可 以很方便地区分每天的日志了,将来查找起来也相当方便。
在配置中启用和关闭日志
在config文件中可以很方便地关闭和启用日志,就是在<root>进行配置,如下就是一个例子:
 
  1. <root> 
  2.   <!--文件形式记录日志--> 
  3.   <appender-ref ref="LogFileAppender" /> 
  4.   <!--控制台控制显示日志--> 
  5.   <appender-ref ref="ConsoleAppender" /> 
  6.   <!--Windows事件日志--> 
  7.   <!--<appender-ref ref="EventLogAppender" />--> 
  8.   <!--SQLite事件日志--> 
  9.   <appender-ref ref="AdoNetAppender_SQLite" /> 
  10.   <!--RollingFileAppender事件日志--> 
  11.   <appender-ref ref="RollingFileAppender" /> 
  12.   <!--RollingFileAppender事件日志,每天一个日志--> 
  13.   <appender-ref ref="RollingLogFileAppender_DateFormat" /> 
  14.   <!-- 如果不启用相应的日志记录,可以通过这种方式注释掉  
  15.   <appender-ref ref="AdoNetAppender_Access" /> 
  16.   --> 
  17. </root> 
在上面的例子中可以看出,如果想增加日志输出目的地,增加<appender-ref>节点就是了,注意后面的ref是在config中配置的appender name,如果想要取消,删除或者注释掉这行就可以了。
Log4Net的使用
首先要添加config文件,在类库项目、命令行程序及WinForm中添加的是app.config,在WebForm中添加的是web.config。
下面是一个在WinForm项目中的使用Log4Net的例子:
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using log4net;  
  5. using System.Reflection;  
  6.  
  7. //注意下面的语句一定要加上,指定log4net使用.config文件来读取配置信息  
  8. //如果是WinForm(假定程序为MyDemo.exe,则需要一个MyDemo.exe.config文件)  
  9. //如果是WebForm,则从web.config中读取相关信息  
  10. [assembly: log4net.Config.XmlConfigurator(Watch = true)]  
  11. namespace Log4NetDemo  
  12. {  
  13.     class Program  
  14.     {  
  15.         static void Main(string[] args)  
  16.         {  
  17.             Random random = new Random();  
  18.             for (int i = 0; i < 1; i++)  
  19.             {  
  20.                 //创建日志记录组件实例  
  21.                 //ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);  
  22.  
  23.                 ILog log=log4net.LogManager.GetLogger(typeof(Program));  
  24.                 //记录错误日志  
  25.                 //log.Error("error", new Exception("在这里发生了一个异常,Error Number:"+random.Next()));  
  26.                 //记录严重错误  
  27.                 //log.Fatal("fatal", new Exception("在发生了一个致命错误,Exception Id:"+random.Next()));  
  28.                 //记录一般信息  
  29.                 //log.Info("提示:系统正在运行");  
  30.                 //记录调试信息  
  31.                 //log.Debug("调试信息:debug");  
  32.                 //记录警告信息  
  33.                 //log.Warn("警告:warn");  
  34.             }  
  35.             Console.WriteLine("日志记录完毕。");  
  36.             Console.Read();  
  37.  
  38.         }  
  39.     }  
在WebForm中也可以使用Log4net,下面是一个在ASP.NET中使用Log4Net的例子:
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Web;  
  4. using System.Web.UI;  
  5. using System.Web.UI.WebControls;  
  6. using log4net;  
  7. using System.Reflection;  
  8.  
  9. [assembly: log4net.Config.XmlConfigurator(Watch = true)]  
  10. public partial class _Default : System.Web.UI.Page   
  11. {  
  12.     protected void Page_Load(object sender, EventArgs e)  
  13.     {  
  14.         if (!Page.IsPostBack)  
  15.         {  
  16.             Random random = new Random();  
  17.             for (int i = 0; i < 1; i++)  
  18.             {  
  19.                 //创建日志记录组件实例  
  20.                 ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);  
  21.  
  22.                 //ILog log = log4net.LogManager.GetLogger(typeof(Program));  
  23.                 //记录错误日志  
  24.                 //log.Error("error", new Exception("在这里发生了一个异常,Error Number:"+random.Next()));  
  25.                 //记录严重错误  
  26.                 //log.Fatal("fatal", new Exception("在发生了一个致命错误,Exception Id:"+random.Next()));  
  27.                 //记录一般信息  
  28.                 //log.Info("提示:系统正在运行");  
  29.                 //记录调试信息  
  30.                 //log.Debug("调试信息:debug");  
  31.                 //记录警告信息  
  32.                 log.Warn("警告:warn");  
  33.                 Response.Write("日志记录完毕。");  
  34.             }  
  35.         }  
  36.     }  

可以看出它们的代码基本没有区别。

下面是一个在WinForm下的config文件的完整配置,该配置文件所使用的代码就是在上面所使用到的代码,使用 LogFileAppender、ConsoleAppender、EventLogAppender、AdoNetAppender_SQLite、 RollingFileAppender、RollingLogFileAppender_DateFormat方式记录日志都在本地通过测试。完整的 config请见附件。

总结:

本篇主要是补充在上一篇关于Log4Net中未尽之处,并集中详尽回答了一些朋友在该篇博文下的提问,如有未尽之处,请在本篇下留言。如有初学者碰巧路过不知config文件为何物,请看《asp.net夜话之十一:web.config详解》,网址是:http://zhoufoxcn.blog.51cto.com/792419/166441

周公
2010-11-23

本文出自 “周公的专栏” 博客,请务必保留此出处http://zhoufoxcn.blog.51cto.com/792419/429988

log4net 的用法

1.引入log4net.dll

2.创建一个log4net.config(名字任意取)内容如下

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net" >
      <param name="File" value="log/" />
      <param name="AppendToFile" value="true" />
      <param name="RollingStyle" value="Date" />
      <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" />
      <param name="StaticLogFileName" value="false" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%n%r %p[%d %c] %m%n" />
      </layout>
    </appender>
    <root>
      <level value="ALL" />
      <appender-ref ref="rollingFile" />
    </root>

    <logger name="*">
      <level value="ALL" />
      <appender-ref ref="rollingFile" />
    </logger>
  </log4net>
</configuration>

3.在工程的AssemblyInfo.cs文件中添加如下语句:

    [assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.config")]

4.最后在需要记录日志的aspx.cs或cs类里,先定义一个log日志对象:

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

5.在需要记录日志的代码块处,加一行这个测试

log.Debug("XX的操作被记录了");

6.对log4net.config中的“%d %t %p %l %m %n”一一讲解:

%d:输出日志时间点的日期或时间,可以在其后指定格式,比如:%d{yyyy-mm-dd hh:mm:ss},输出类似:2005-7-19 17:49:27,刚好适合插入sqlserver;

 
 
%t:产生该日志事件的线程名;

 
 
%p:日志的log_level,如debug、warn或者info;

 
 
%c:输出所属的类目,通常就是所在类的全名,如“inotes.default”;

 
 
%m:日志的内容;

 
 
%l:输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。

 
 
%n  输出一个回车换行符,windows平台为“\r\n”,unix平台为“\n”

http://blog.csdn.net/CHENFEIYANG2009/archive/2010/03/19/5397342.aspx

1、概述

log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的格式,输 出到不同的媒介。本文主要是介绍如何在Visual Studio2008中使用log4net快速创建系统日志,如何扩展以输出自定义字段。

2、一个简单的使用实例

第一步:在项目中添加对log4net.dll的引用,这里引用版本是1.2.10.0。

第二步:程序启动时读取log4net的配置文件。

如果是CS程序,在根目录的Program.cs中的Main方法中添加:

log4net.Config.XmlConfigurator.Configure();

如果是BS程序,在根目录的Global.asax.cs(没有新建一个)中的Application_Start方法中添加:

log4net.Config.XmlConfigurator.Configure();

无论BS还是CS程序都可直接在项目的AssemblyInfo.cs文件里添加以下的语句:

[assembly: log4net.Config .XmlConfigurator()]

也可以使用自定义的配置文件,具体请参见4.4 关联配置文件。

第三步:修改配置文件。如果是CS程序,则在默认的App.config文件(没有新建一个)中添加内容;如果是BS程序,则添加到Web.config文件中,添加内容一样,这里不再列出。

App.config文件添加内容如下:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

<section name="log4net"

type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

  </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] "/>

        <param name="Footer" value="[Footer] "/>

        <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.ILog log = log4net.LogManager.GetLogger("testApp.Logging");//获取一个日志记录器

log.Info(DateTime.Now.ToString() + ": login success");//写入一条新log

这样就将信息同时输出到控制台和写入到文件名为“log-file.txt”的文件中,其中“log-file.txt”文件的路径是当前程序运行所在目录;也可以定义为绝对路径,配置如:

<param name="File" value="C:\log-file.txt" />就写入C盘根目录下log-file.txt文件中,具体使用技巧参见4.2.1。

本例的实现请参见8.6附件。

3、Log4net的主要组成部分

3.1 Appenders

Appenders用来定义日志的输出方式,即日志要写到那种介质上去。较常用的Log4net已经实现好了,直接在配置文件中调用即可,可参见上 面配置文件例子;当然也可以自己写一个,需要从log4net.Appender.AppenderSkeleton类继承。它还可以通过配置 Filters和Layout来实现日志的过滤和输出格式。

已经实现的输出方式有:

AdoNetAppender 将日志记录到数据库中。可以采用SQL和存储过程两种方式。

AnsiColorTerminalAppender 将日志高亮输出到ANSI终端。

AspNetTraceAppender  能用asp.net中Trace的方式查看记录的日志。

BufferingForwardingAppender 在输出到子Appenders之前先缓存日志事件。

ConsoleAppender 将日志输出到应用程序控制台。

EventLogAppender 将日志写到Windows Event Log。

FileAppender 将日志输出到文件。

ForwardingAppender 发送日志事件到子Appenders。

LocalSyslogAppender 将日志写到local syslog service (仅用于UNIX环境下)。

MemoryAppender 将日志存到内存缓冲区。

NetSendAppender 将日志输出到Windows Messenger service.这些日志信息将在用户终端的对话框中显示。

OutputDebugStringAppender 将日志输出到Debuger,如果程序没有Debuger,就输出到系统Debuger。如果系统Debuger也不可用,将忽略消息。

RemoteSyslogAppender 通过UDP网络协议将日志写到Remote syslog service。

RemotingAppender 通过.NET Remoting将日志写到远程接收端。

RollingFileAppender 将日志以回滚文件的形式写到文件中。

SmtpAppender 将日志写到邮件中。

SmtpPickupDirAppender 将消息以文件的方式放入一个目录中,像IIS SMTP agent这样的SMTP代理就可以阅读或发送它们。

TelnetAppender 客户端通过Telnet来接受日志事件。

TraceAppender 将日志写到.NET trace 系统。

UdpAppender 将日志以无连接UDP数据报的形式送到远程宿主或用UdpClient的形式广播。

3.2 Filters

使用过滤器可以过滤掉Appender输出的内容。过滤器通常有以下几种:

DenyAllFilter 阻止所有的日志事件被记录

LevelMatchFilter 只有指定等级的日志事件才被记录

LevelRangeFilter 日志等级在指定范围内的事件才被记录

LoggerMatchFilter 与Logger名称匹配,才记录

PropertyFilter 消息匹配指定的属性值时才被记录

StringMathFilter 消息匹配指定的字符串才被记录

3.3 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的格式化字符串见文后附注8.1。

3.4 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");

3.5 Object Renders

它将告诉logger如何把一个对象转化为一个字符串记录到日志里。(ILog中定义的接口接收的参数是Object,而不是String。)

例如你想把Orange对象记录到日志中,但此时logger只会调用Orange默认的ToString方法而已。所以要定义一个 OrangeRender类实现log4net.ObjectRender.IObjectRender接口,然后注册它(我们在本文中的扩展不使用这种 方法,而是直接实现一个自定义的Layout)。这时logger就会知道如何把Orange记录到日志中了。

3.6 Repository

Repository主要用于日志对象组织结构的维护。

4、配置文件详解

4.1 配置文件构成

主要有两大部分,一是申明一个名为“log4net“的自定义配置节,如下所示:

  <configSections>

<section name="log4net"

type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

  </configSections>

二是<log4net>节的具体配置,这是下面要重点说明的。

4.1.1<log4net>

所有的配置都要在<log4net>元素里定义。

支持的属性:

debug

可选,取值是true或false,默认是false。设置为true,开启log4net的内部调试。

update

可选,取值是Merge(合并)或Overwrite(覆盖),默认值是Merge。设置为Overwrite,在提交配置的时候会重置已经配置过的库。

threshold

可选,取值是repository(库)中注册的level,默认值是ALL。

支持的子元素:

appender

0或多个

logger

0或多个

renderer

0或多个

root

最多一个

param

0或多个

 

4.1.2 <root>

实际上就是一个根logger,所有其它logger都默认继承它,如果配置文件里没有显式定义,则框架使用根日志中定义的属性。root元素没有属性。

支持的子元素:

appender-ref

0个或多个,要引用的appender的名字。

level

最多一个。 只有在这个级别或之上的事件才会被记录。

param

0个或多个, 设置一些参数。

 

4.1.3 <logger>

支持的属性:

name

必须的,logger的名称

additivity

可选,取值是true或false,默认值是true。设置为false时将阻止父logger中的appender。

支持的子元素:

appender-ref

0个或多个,要引用的appender的名字。

level

最多一个。 只有在这个级别或之上的事件才会被记录。

param

0个或多个, 设置一些参数。

 

4.1.4 <appender>

定义日志的输出方式,只能作为 log4net 的子元素。name属性必须唯一,type属性必须指定。

支持的属性:

name

必须的,Appender对象的名称

type

必须的,Appender对象的输出类型

支持的子元素:

appender-ref

0个或多个,允许此appender引用其他appender,并不是所以appender类型都支持。

filter

0个或多个,定义此app使用的过滤器。

layout

最多一个。定义appender使用的输出格式。

param

0个或多个, 设置Appender类中对应的属性的值。

实际上<appender>所能包含的子元素远不止上面4个。

 

4.1.5 <layout>

布局,只能作为<appender>的子元素。

支持的属性:

type

必须的,Layout的类型

支持的子元素:

param

0个或多个, 设置一些参数。

 

4.1.6 <filter>

过滤器,只能作为<appender>的子元素。

支持的属性:

type

必须的,Filter的类型

支持的子元素:

param

0个或多个, 设置一些参数。

 

4.1.7 <param>

<param>元素可以是任何元素的子元素。

支持的属性:

name

必须的,取值是父对象的参数名。

value

可选的,value和type中,必须有一个属性被指定。value是一个能被转化为参数值的字符串。

type

可选的,value和type中,必须有一个属性被指定。type是一个类型名,如果type不是在log4net程序集中定义的,就需要使用全名。

支持的子元素:

param

0个或多个, 设置一些参数。

 

4.2 <appender>配置

   <appender>在配置文件中至少有一个,也可以有多个,有些<appender>类型还可以引用其他<appender>类型,具体参数可参见上表。

下面只对写入回滚文件与输出到数据库(这里使用SQL数据库)配置体会说一下,其他配置可参考官方网站:http://logging.apache.org/log4net/release/config-examples.html

4.2.1写入回滚文件

    <appender name="ReflectionLayout" type="log4net.Appender.RollingFileAppender,log4net">

<!--日志文件路径,“/”与“\”作用相同,到达的目录相同,文件夹不存在则新建 -->

<!--按文件大小方式输出时在这里指定文件名,并且当天的日志在下一天时在文件名后自动追加当天日期形成新文件。-->

<!—按照日期形式输出时,直接连接元素DatePattern的value形成文件路径。此处使用这种方式 -->

<!--param的名称,可以直接查对应的appender类的属性名即可,这里要查的就是RollingFileAppender类的属性 -->

      <param name="File" value="D:/Log/" />

 

      <!--是否追加到文件-->

      <param name="AppendToFile" value="true" />

 

      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->

      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

 

      <!—使用Unicode编码-->

      <Encoding value="UTF-8" />

 

      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->

      <param name="MaxSizeRollBackups" value="10" />

 

      <!--是否只写到一个文件中-->

      <param name="StaticLogFileName" value="false" />

 

      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->

      <param name="RollingStyle" value="Composite" />

 

      <!--按日期产生文件夹和文件名[在日期方式与混合方式下使用]-->

<!—此处按日期产生文件夹,文件名固定。注意&quot; 的位置-->

      <param name="DatePattern" value="yyyy-MM-dd/&quot;ReflectionLayout.log&quot;"  />

<!—这是按日期产生文件夹,并在文件名前也加上日期-->

      <param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-TimerServer.log&quot;"  />

<!—这是先按日期产生文件夹,再形成下一级固定的文件夹—>

      <param name="DatePattern" value="yyyyMMdd/&quot;TimerServer/TimerServer.log&quot;"  />

 

      <!--每个文件的大小。只在混合方式与文件大小方式下使用。

超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。

可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->

      <param name="maximumFileSize" value="500KB" />

 

<!--计数类型为1,2,3…-->
      <param name="CountDirection" value="1"/>

 

<!—过滤设置,LevelRangeFilter为使用的过滤器。 -->

      <filter type="log4net.Filter.LevelRangeFilter">

        <param name="LevelMin" value="DEBUG" />

        <param name="LevelMax" value="WARN" />

      </filter>

 

      <!--记录的格式。一般用log4net.Layout.PatternLayout布局-->

<!—此处用继承了log4net.Layout.PatternLayout的自定义布局,TGLog.ExpandLayout2

为命名空间。%property{Operator}、%property{Action}是自定义的输出-->

      <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

        <param name="ConversionPattern"

 value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger     操作者ID:%property{Operator} 操作类型:%property{Action}%n             当前机器名:%property%n当前机器名及登录用户:%username %n               记录位置:%location%n 消息描述:%property{Message}%n                    异常:%exception%n 消息:%message%newline%n%n" />

      </layout>

</appender>

注意这些配置属性有些是可选的,如果需要,一定要写正确,否则要么输出的不是自己想要的结果,要么干脆不输出任何信息。

4.2.1写入SQL数据库

需要在相应的数据库中准备好一张表,创建语句如下:

CREATE TABLE [Log] (

[ID] [int] IDENTITY (1, 1) NOT NULL ,

[Date] [datetime] NOT NULL ,

[Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

[Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

[Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,

[Operator] [int] NULL ,

[Message] [text] COLLATE Chinese_PRC_CI_AS NULL ,

[ActionType] [int] NULL ,

[Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL ,

[IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,

[MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,

[Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,

[Location] [text] COLLATE Chinese_PRC_CI_AS NULL ,

[Exception] [text] COLLATE Chinese_PRC_CI_AS NULL

)

<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net">

<!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->

<bufferSize value="10" /><!—或写为<param name="BufferSize" value="10" />-->

 

<!--引用-->

<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

 

<!--连接数据库字符串-->

<connectionString value="data source=.;initial catalog=Test;integrated security=false;persist security info=True;User ID=sa;Password=;" />

 

<!--插入到表Log-->

<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Operator],[Message],[ActionType],[Operand],[IP],[MachineName],[Browser],[Location],[Exception]) VALUES (@log_date, @thread, @log_level, @logger,@operator, @message,@action_type,@operand,@ip,@machineName,@browser,@location,@exception)" />

 

<!—日志记录时间,RawTimeStampLayout为默认的时间输出格式 -->

      <parameter>

        <parameterName value="@log_date" />

        <dbType value="DateTime" />

        <layout type="log4net.Layout.RawTimeStampLayout" />

      </parameter>

 

      <!--线程号-->

      <parameter>

        <parameterName value="@thread" />

        <dbType value="String" />

<!—长度不可以省略,否则不会输出-->

        <size value="100" />

        <layout type="log4net.Layout.PatternLayout">

          <conversionPattern value="%thread" />

        </layout>

      </parameter>

 

      <!--日志等级-->

      <parameter>

        <parameterName value="@log_level" />

        <dbType value="String" />

        <size value="100" />

        <layout type="log4net.Layout.PatternLayout">

          <conversionPattern value="%level" />

        </layout>

      </parameter>

 

      <!--日志记录类名称-->

      <parameter>

        <parameterName value="@logger" />

        <dbType value="String" />

        <size value="200" />

        <layout type="log4net.Layout.PatternLayout">

          <conversionPattern value="%logger" />

        </layout>

      </parameter>

     

      <!--操作者。这个是自定义的输出字段,使用重新实现的布局器ReflectionLayout -->

      <parameter>

        <parameterName value="@operator" />

<!—设置为Int32时只有bufferSize的 value<="1"才正确输出,没有找出原因。-->

        <dbType value="Int16" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{Operator}" />

        </layout>

      </parameter>

 

      <!--操作对象-->

      <parameter>

        <parameterName value="@operand" />

        <dbType value="String" />

        <size value="300" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{Operand}" />

        </layout>

      </parameter>

 

      <!—IP地址-->

      <parameter>

        <parameterName value="@ip" />

        <dbType value="String" />

        <size value="20" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{IP}" />

        </layout>

      </parameter>

 

      <!--机器名-->

      <parameter>

        <parameterName value="@machineName" />

        <dbType value="String" />

        <size value="100" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{MachineName}" />

        </layout>

      </parameter>

 

      <!--浏览器-->

      <parameter>

        <parameterName value="@browser" />

        <dbType value="String" />

        <size value="50" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{Browser}" />

        </layout>

      </parameter>

     

      <!—日志消息-->

      <parameter>

        <parameterName value="@message" />

        <dbType value="String" />

        <size value="3000" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{Message}" />

        </layout>

      </parameter>

 

      <!--动作类型-->

      <parameter>

        <parameterName value="@action_type" />

        <dbType value="Int16" />

        <layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">

          <conversionPattern value="%property{ActionType}" />

        </layout>

      </parameter>

 

      <!—记录日志的位置-->

      <parameter>

        <parameterName value="@location" />

        <dbType value="String" />

        <size value="2000" />

        <layout type="log4net.Layout.PatternLayout">

          <conversionPattern value="%location" />

        </layout>

      </parameter>

     

      <!—异常信息。ExceptionLayout 为异常输出的默认格式-->

      <parameter>

        <parameterName value="@exception" />

        <dbType value="String" />

        <size value="4000" />

        <layout type="log4net.Layout.ExceptionLayout" />

      </parameter>

</appender>

注意:

向表中输出的字段不能多于数据表本身字段,而反之则可以,但这些多余字段一定使其可以为空,否则便写不到数据库;

输出字段的类型一定是对应数据表字段数据类型可以隐式转换的,而且长度也不能超过,否则也不能写入;

数据表字段设置尽量可以为空,这样可以避免一条日志记录存在空数据导致后面的日志都记录不了。

4.3<logger>的配置

在配置文件<appender>中的配置好了输出的介质,格式,过滤方式,还要定义日志对象<logger>。

在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在<root>标签里,可以定义level级别值和 Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过<appender-ref>标签定义日志对象使用的 Appender对象。<appender-ref>声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设 置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设 定<logger>标签的additivity属性为false而改变。

<root>不显式申明时使用默认的配置。我觉得在使用时不定义<root>,自定义多个<logger>, 在程序中记录日志时直接使用<logger>的name来查找相应的<logger>,这样更灵活一些。例如:

<!--同时写两个文件和数据库-->

<logger name="ReflectionLayout">

      <level value="DEBUG"/>

      <appender-ref ref="HashtableLayout"/>

      <appender-ref ref="ReflectionLayout"/>

      <appender-ref ref="ADONetAppender"/>

</logger>

4.4关联配置文件

log4net默认关联的是应用程序的配置文件App.config(BS程序是Web.config),可以使用程序集自定义属性来进行设置。下面来介绍一下这个自定义属性:

log4net.Config.XmlConifguratorAttribute。

XmlConfiguratorAttribute有3个属性:

ConfigFile: 配置文件的名字,文件路径相对于应用程序目录

(AppDomain.CurrentDomain.BaseDirectory)。ConfigFile属性不能和ConfigFileExtension属性一起使用。

ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension属性不能和ConfigFile属性一起使用。

Watch: 如果将Watch属性设置为true,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。

如果ConfigFile和ConfigFileExtension都没有设置,则使用应用程序的配置文件App.config(Web.config)。

可以在项目的AssemblyInfo.cs文件里添加以下的语句:

 //监视默认的配置文件,App.exe.config   

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

 

//监视配置文件,App.exe.log4net。

[assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]

 

//使用配置文件log4net.config,不监视改变。注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下,如调试时在\bin\Debug下,一般将文件属性的文件输出目录调为//始终复制即可

[assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")]

 

//使用配置文件log4net.config,不监视改变

[assembly: log4net. Config.XmlConfigurator()]

也可以在Global.asax的Application_Start里或者是Program.cs中的Main方法中添加,注意这里一定是绝对路径,如下所示:

//这是在BS程序下,使用自定义的配置文件log4net.xml,使用Server.MapPath("~") + //@"\log4net.xml”来取得路径。 \log4net.xml为相对于站点的路径

// ConfigureAndWatch()相当于Configure(Watch = true)

log4net.Config.XmlConfigurator.ConfigureAndWatch(

new System.IO.FileInfo(Server.MapPath("~") + @"\log4net.xml"));

//这是在CS程序下,可以用以下方法获得:

string assemblyFilePath = Assembly.GetExecutingAssembly().Location;

string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);

string configFilePath = assemblyDirPath + " ";

log4net.Config.XmlConfigurator.ConfigureAndWatch(

new FileInfo(configFilePath));

或直接使用绝对路径:

//使用自定义的配置文件,直接绝对路径为:c:/log4net.config

log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));

5、如何记录日志

Log4net使用很方便,先申明一个封装类ILog 的对象,如下:

log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");

其中"ReflectionLayout"便是我们自定义的日志对象<logger>的name的值。

对应5个日志输出级别,log有5 个方法,每个方法都有两个重载,使用如下:

try

            {

                log.Debug("这是一个测试!");

            }

            catch(Exception ec)

            {

                log.Error("出现错误!", ec);

         }

如果我们需要输出的消息是要区别开来,不按一个字符串全部输出,就需要进行一些扩展了。

posted @ 2011-08-24 14:55  董雨  阅读(338)  评论(0编辑  收藏  举报