log4net 记录 总结 反思

说实话,我并不是太想写这篇文章,因为我承诺过要完成博客园的部分功能,所以一直都在积极的利用下班时间来完善这个系统,

但是我又不想让看我源代码的朋友不知道我写的代码是什么意思,所以我还是单独写一个文章,叙述一下我对管理日志的看法,

当然主要是log4net的使用。为了写这篇文章,我查看了博客园的很多关于log4net的文章,但是结果令我很不满意,因为他们对于log4net的介绍基本上都是大同小异,

我不敢说他们写的有错,因为确实就是那么写的,但是为什么我还要写这篇博客呢,因为我想以一个学习者的心态来分析这个框架结构,而不是以一个老师来分析。

从一个学习者到老师需要很多的路要走的,他们都省略了学习者入门时的困难,所以我决定还是来写一篇博客来叙述一下。希望大家吐槽。
  首先,现在系统越来越复杂,并且集成的模块也越来越多,在测试系统的时候我们可以利用单元测试(有单元测试框架支持,比如nunit等),

还可以通过认为的点击来测试系统功能的正常,在开发过程中我们可以测试出来很多的问题。但是在系统已经部署到服务器上以后,我们就不能进行单元测试了,

因为部署到服务器上的不是源码,当然也有其他的方式可以测试系统bug,但是在实际环境中会出现很多令人意想不到的问题。举个简单的例子,虽然我们会在系统中进行异常的捕获,

并且会显示特定的错误信息,但是错误信息是对用户显示的,我们开发者当然希望知道错误的详细信息,以便我们可以改正错误。这是必须的,所以最简单也最直接的方式就出现了,

就是记录系统日志,当然如果不采用log4net日志管理框架,我们也是可以通过文件操作来写入日志,但是这个不便于配置。正如我听到的一个老师说的,

如果你的系统要进行扩展,那么你会怎么办?这是当时很令我头疼的一个问题,但是我现在基本知道思路,就是采用分层开发模式,将不同的层放到对应的类库中,

另外我们也可以采用IOC(依赖注入)或者Nhibernate等框架来提高系统的灵活性。

 废话太多,大家都会没有耐心看下去,但是如果这是代码,我估计大家更不会看下去。呵呵

  因为园子里有很多介绍log4net的介绍,所以我就不详细的介绍了,我只说我个人认为在开发中是重点的,欢迎大家吐槽~~

  我们知道log4net有一个姐妹叫log4j,他们是针对.Net和java开发的两个结构基本相同的框架结构,


看到这种说法,我一直想说,为什么好的框架都会从java移植而来,并且都是apache这个组织开发的呢?这里面也不是我能理解的,我也是吐槽一下。

   log4net主要由Appender,Logger,Filter,Layout和一个Object Render组成。

其中

      Appender(附着器)主要用来确定日志记录的位置,也可以这么说就是确定日志是记录到数据库还是文件或其他终端。

       Logger(记录器),记录器 看字面意思就应该可以猜到他就是用来确定要发送的日志信息。比如说,有一个异常发生,我们需要记录什么数据,都是由Logger负责的。

 

       Filter(过滤器) 可以这么理解,这个和MVC中的Filter还是有差别的,这里的Filter表示的是过滤,就像筛子 可以过滤一样,而MVC中的Filter也可以叫做过滤器,但是它更多的是完成

Aop(面向切面或面向方面) 的横向的过滤导向,也可以认为是对某个Action或Controller施加的限制。

 

     Layout(布局) 布局很容易理解,就像装修一样,把我们要记录的数据整理成我们需要的格式。

 

至于后面的object render,我在官方文章看了一下,个人理解就相当于渲染输出,就像服务器发送html到浏览器以后,浏览器要渲染输出的效果应该是一样。

 

简单的描述了一下log4net的组成,还有很重要的就是log4net的分级,其中log4net一种氛围5级,按从高到低的顺序依次为:

off>fatal>Error>Warn>Info>Debug>All

看到这个分级,大家一定要骂我了,一共有七个值,偏偏说5个分级,这里我解释一下,off的意思就是关闭log4net的日志输出,

    fatal的级别最高,表示的就是特别严重的错误,一般是在应用程序崩溃的时候,而error则是表示错误出现,一般用在出现了异常以后,

   Warn表示警告,这个不会使程序出现异常,但是可能会影响程序性能,info 和debug则可以随意了。另外all表示的就是所有的分级都可以满足。

    这里大家要注意一下的就是,这个分级是会影响程序日志输出的。比如说你在程序中定义了 log.Info(message) 和log.debug(message),但是你定义的日志应当输出的级别是info,很抱歉

的告诉你,log.debug(message)中的信息不会写入日志,因为debug在顺序中是小于info的。

 

     说了log4net中最重要的两个部分,现在就需要正式的启用log4net来输出日志信息了,签于园友们都有很详细的配置信息,所以我就把主要的两个简单的描述一下,如果有需要我会在注释中

写入的。在项目中我们一般会用到输出日志到文件或者数据库中,这两种方式,我个人也非常喜欢这两种方式。一般我会把日志同时输出到文件和数据库中,虽然会有一点的性能损失,但是对于

日志的完整性还是十分值得的,当然输出的日志越少性能会越高,大家都懂得。

    log4net是支持配置文件来更改其输出方式的,我们可以把配置文件放到项目配置文件web.config或winform的app.config中,也可以单独的放到固定的配置文件中,现在我们把配置文件放

到项目配置文件中。

配置文件如下

 
  1 <configSections>
  2     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/><!--配置一个结点 名称为log4net-->
  3   </configSections>
  4   <log4net debug="true">
  5     <appender name="LogFileAppender" type="log4net.Appender.FileAppender" > <!--定义的是日志记录到文件的附着器 name表示该附着器的名称-->
<!--在log4net中还有一个附着器RollingFileAppender 它表示会循环生成很多文件,举例来说,就是设置一共可以生成20个文件,每个文件的大小为2K,那么如果第一个-->、
<!--文件的大小超过2K,就会自动创建一个按顺序命名的文件--> 6 <param name="File" value="c:\Log\DBLog.txt" /> <!--日志记录的存在路径--> 7 <param name="AppendToFile" value="true" /><!--为true就表示日志会附加到文件,为false,则会重新创建一个新文件--> 8 <layout type="log4net.Layout.PatternLayout"><!--输出内容控制--> 9 <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" /> 10 </layout> 11 </appender> 12 <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender"><!--设置发送电子邮件的附着器--> 13 <authentication value="Basic" /> 14 <to value="guozhiqi@babaike.com" /> 15 <from value="guozhiqi21@163.com" /> 16 <username value="guozhiqi21" /> 17 <password value="password" /> 18 <subject value="测试错误信息显示" /> 19 <smtpHost value="smtp.163.com" /> 20 <bufferSize value="512" /> 21 <lossy value="true" /> 22 <evaluator type="log4net.Core.LevelEvaluator"> 23 <threshold value="debug"/> 24 </evaluator> 25 <layout type="log4net.Layout.PatternLayout"> 26 <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" /> 27 </layout> 28 </appender> 29 <!--<logger name="smtp"> 30 <level value="debug"/> 31 <appender-ref ref="SmtpAppender"/> 32 </logger>--> 33 <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"><!--存储到数据库的操作--> 34 <bufferSize value="10"/> 35 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 36 <connectionString value="server=192.168.1.66;database=教学;user id=sa;password=sa1234"/> 37 <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date,
@log_thread, @log_level, @log_logger, @log_message, @log_exception)
"/> 38 <parameter> 39 <parameterName value="@log_date"/> 40 <dbType value="DateTime"/> 41 <layout type="log4net.Layout.RawTimeStampLayout"/><!--可以认为是记录日志的时间--> 42 </parameter> 43 <parameter> 44 <parameterName value="@log_thread"/> 45 <dbType value="String"/> 46 <size value="255"/> 47 <layout type="log4net.Layout.PatternLayout"> 48 <conversionPattern value="%thread"/><!--记录日志时的线程号--> 49 </layout> 50 </parameter> 51 <parameter> 52 <parameterName value="@log_level"/> 53 <dbType value="String"/> 54 <size value="50"/> 55 <layout type="log4net.Layout.PatternLayout"> 56 <conversionPattern value="%level"/><!--日志级别--> 57 </layout> 58 </parameter> 59 <parameter> 60 <parameterName value="@log_logger"/> 61 <dbType value="String"/> 62 <size value="255"/> 63 <layout type="log4net.Layout.PatternLayout"> 64 <conversionPattern value="%logger"/><!--哪个记录器存储的该日志--> 65 </layout> 66 </parameter> 67 <parameter> 68 <parameterName value="@log_message"/> 69 <dbType value="String"/> 70 <size value="4000"/> 71 <layout type="log4net.Layout.PatternLayout"> 72 <conversionPattern value="%message"/><!--日志信息--> 73 </layout> 74 </parameter> 75 <parameter> 76 <parameterName value="@log_exception"/> 77 <dbType value="String"/> 78 <size value="255"/> 79 <layout type="log4net.Layout.ExceptionLayout"/><!--异常信息--> 80 </parameter> 81 </appender> 82 <appender name="RollingFile" type="log4net.Appender.RollingFileAppender"><!--这个就是我在上面提到的RolllingFileAppender--> 83 <file value="example.log" /><!--文件名称--> 84 <appendToFile value="false" /><!--会创建新文件,一般设置为true,这里设置为false,是为了看到创建的文件--> 85 <maximumFileSize value="1KB" /><!--文件大小--> 86 <maxSizeRollBackups value="20" /><!--创建最大文件数--> 87 <layout type="log4net.Layout.PatternLayout"> 88 <conversionPattern value="%level %thread %logger - %message%newline" /> 89 </layout> 90 </appender> 91 <!--<logger name="rolling"> 92 <level value="fatal"/> 93 <appender-ref ref="RollingFile"/> 94 <appender-ref ref="ADONetAppender"/> 95 </logger>--> 96 <root> 97 <level value="info" /> 98 <appender-ref ref="ADONetAppender" /> 99 <appender-ref ref="SmtpAppender"/>--> 100 <appender-ref ref="LogFileAppender"/> 101 <appender-ref ref="ColoredConsoleAppender"/> 102 <appender-ref ref="EventLogAppender"/> 103 <append-ref ref="NetSendAppender"/> 104 <appender-ref ref="RollingFile"/> 105 </root> 106 </log4net>
在配置文件创建好了以后,按道理说就可以在程序中使用log4net了,创建Log4NetController,在该控制器中进行对log4net的测试
 1   public class Log4netController : Controller
 2     {
 3 
 4         private static readonly log4net.ILog log = log4net.LogManager.GetLogger("rolling");
 5 
 6         public ActionResult Index()
 7         {
 8             log4net.Config.XmlConfigurator.Configure();
 9 
10             log.Info("log日志信息");
11             log.Debug("debug信息");
12             log.Error("error信息");
13             log.Warn("warn信息");
14             Exception ex = new Exception("这里显示的是异常信息");
15             log.Fatal("fatal信息", ex);
16             return View();
17         }
18 
19     }

运行程序,就可以在数据库中看到日志生成的记录


      说明log4net的日志记录到数据库是正确的。下面我们来分析一下,因为我是在把代码复制到博客中才加的注释,所以不是C#标准的注释方式,

      下面我们来把使用log4net中要注意的地方或者我认为是会令人疑惑的地方叙述一下,

  1. 其实我们在配置log4net的时候最好是直接复制原来可以运行的配置文件,然后进行修改,因为如果你的配置文件有一点错误,那么log4net都不会正常工作的,

    这里还有一个更严重的问题就是我们不会得到log4net引发的任何异常。我们只能是慢慢修改,有耐心,最好是复制 粘贴

  2. <!--<logger name="rolling">
     92       <level value="fatal"/>
     93       <appender-ref ref="RollingFile"/>
     94       <appender-ref ref="ADONetAppender"/>
     95     </logger>-->
     96     <root>
     97       <level value="info" />
     98       <appender-ref ref="ADONetAppender" />
     99       <appender-ref ref="SmtpAppender"/>-->
    100       <appender-ref ref="LogFileAppender"/>
    101       <appender-ref ref="ColoredConsoleAppender"/>
    102       <appender-ref ref="EventLogAppender"/>
    103       <append-ref ref="NetSendAppender"/>
    104       <appender-ref ref="RollingFile"/>
    105     </root>

这段代码中的root和logger结点我们需要注意一下,因为在root中定义的是针对所有的logger,也就是说如果你在程序中使用的不是LogManager.getLogger(Loggername)这种方式,那么你默认的会使用root结点的配置信息来记录日志,而如果你使用了这种方式,那么就会使用对应的logger结点的配置信息。

 3.log4net是可配置、可修改的灵活日志输出,我们必须在程序中对log4net进行配置。

 log4net.Config.XmlConfigurator.Configure(); 这个是默认的配置方式,当然我们也可以利用参数中加入配置文件路径来指定配置文件。这个是必须要配置的,切记。

还有就是这个配置应当是在程序启动时就需要配置完成,因此在application_start中是比较好的方法。

4.log4net输出日志的时候我们看到了很多的%形式,这是表示的什么意思呢?其实%thread 就是表示当前的线程名称,%level就是表示日志的级别。

5.最后我还想补充一下,任何和程序执行无关的代码都会影响程序的性能,日志的输出和程序功能的完成没有直接的关系,过多的日志输出会影响程序响应的性能,另外我们要控制删除日志的级别,以便不要任何日志信息都会输出。

6.通过 private static readonly log4net.ILog log = log4net.LogManager.GetLogger("rolling"); 可以的到一个log对象,但是我们如何确定是否需要输出到对应的级别呢?

log4net提供了

我们可以通过这几个属性来判断是否需要输出不同级别的日志。
暂时想到的就这么多,我想到别的还会加上,欢迎吐槽

补充一下:
 1   <appender name="RollingLogRootFileAppender" type="log4net.Appender.RollingFileAppender">
 2       <!--日志的路径-->
 3       <file value="..\temp\log\Winlog" />
 4       <!--是否覆盖,默认是追加true-->
 5       <appendToFile value="true"/>
 6       <!--文件滚动周期(每日创建新日志文件)-->
 7       <datePattern value="yyyyMMdd&quot;.txt&quot;"/>
 8       <!--设置无限备份=-1 ,最大备份数为1000-->
 9       <maxSizeRollBackups value="1000"/>
10       <!--名称是否可以更改为false为可以更改-->
11       <staticLogFileName value="false" />
12       <!--文件滚动选项Composite表示根据日期和大小来滚动-->
13       <rollingStyle value="Composite" />
14       <layout type="log4net.Layout.PatternLayout">
15         <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%t][%-5p][%c]%m%n%exception%n" />
16       </layout>
17     </appender>
这个可以用来对RolingFile进行更好的控制

   

posted @ 2012-12-27 09:44  baidixing  阅读(6848)  评论(19编辑  收藏  举报