当前位置: 代码迷 >> 综合 >> log4net 记录 总结
  详细解决方案

log4net 记录 总结

热度:5   发布时间:2024-01-30 18:28:28.0

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

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

当然主要是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中,也可以单独的放到固定的配置文件中,现在我们把配置文件放

到项目配置文件中。

配置文件如下

 
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/><!--配置一个结点 名称为log4net-->
</configSections>
<log4net debug="true">
<appender name="LogFileAppender" type="log4net.Appender.FileAppender" > <!--定义的是日志记录到文件的附着器 name表示该附着器的名称-->
<!--在log4net中还有一个附着器RollingFileAppender 它表示会循环生成很多文件,举例来说,就是设置一共可以生成20个文件,每个文件的大小为2K,那么如果第一个-->、
<!--文件的大小超过2K,就会自动创建一个按顺序命名的文件-->
<param name="File" value="c:\Log\DBLog.txt" /> <!--日志记录的存在路径-->
<param name="AppendToFile" value="true" /><!--为true就表示日志会附加到文件,为false,则会重新创建一个新文件-->
<layout type="log4net.Layout.PatternLayout"><!--输出内容控制-->
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />
</layout>
</appender>
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender"><!--设置发送电子邮件的附着器-->
<authentication value="Basic" />
<to value="guozhiqi@babaike.com" />
<from value="guozhiqi21@163.com" />
<username value="guozhiqi21" />
<password value="password" />
<subject value="测试错误信息显示" />
<smtpHost value="smtp.163.com" />
<bufferSize value="512" />
<lossy value="true" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="debug"/>
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
</layout>
</appender>
<!--<logger name="smtp">
<level value="debug"/>
<appender-ref ref="SmtpAppender"/>
</logger>-->
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"><!--存储到数据库的操作-->
<bufferSize value="10"/>
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<connectionString value="server=192.168.1.66;database=教学;user id=sa;password=sa1234"/>
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, 
@log_thread, @log_level, @log_logger, @log_message, @log_exception)"/>
<parameter>
<parameterName value="@log_date"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout"/><!--可以认为是记录日志的时间-->
</parameter>
<parameter>
<parameterName value="@log_thread"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread"/><!--记录日志时的线程号-->
</layout>
</parameter>
<parameter>
<parameterName value="@log_level"/>
<dbType value="String"/>
<size value="50"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level"/><!--日志级别-->
</layout>
</parameter>
<parameter>
<parameterName value="@log_logger"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger"/><!--哪个记录器存储的该日志-->
</layout>
</parameter>
<parameter>
<parameterName value="@log_message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/><!--日志信息-->
</layout>
</parameter>
<parameter>
<parameterName value="@log_exception"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.ExceptionLayout"/><!--异常信息-->
</parameter>
</appender>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender"><!--这个就是我在上面提到的RolllingFileAppender-->
<file value="example.log" /><!--文件名称-->
<appendToFile value="false" /><!--会创建新文件,一般设置为true,这里设置为false,是为了看到创建的文件-->
<maximumFileSize value="1KB" /><!--文件大小-->
<maxSizeRollBackups value="20" /><!--创建最大文件数-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level %thread %logger - %message%newline" />
</layout>
</appender>
<!--<logger name="rolling">
<level value="fatal"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="ADONetAppender"/>
</logger>-->
<root>
<level value="info" />
<appender-ref ref="ADONetAppender" />
<appender-ref ref="SmtpAppender"/>-->
<appender-ref ref="LogFileAppender"/>
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="EventLogAppender"/>
<append-ref ref="NetSendAppender"/>
<appender-ref ref="RollingFile"/>
</root>
</log4net>
在配置文件创建好了以后,按道理说就可以在程序中使用log4net了,创建Log4NetController,在该控制器中进行对log4net的测试
public class Log4netController : Controller
{

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger("rolling");

        public ActionResult Index()
{
log4net.Config.XmlConfigurator.Configure();

            log.Info("log日志信息");
log.Debug("debug信息");
log.Error("error信息");
log.Warn("warn信息");
Exception ex = new Exception("这里显示的是异常信息");
log.Fatal("fatal信息", ex);
return View();
}

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


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

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

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

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

<!--<logger name="rolling">
<level value="fatal"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="ADONetAppender"/>
</logger>-->
<root>
<level value="info" />
<appender-ref ref="ADONetAppender" />
<appender-ref ref="SmtpAppender"/>-->
<appender-ref ref="LogFileAppender"/>
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="EventLogAppender"/>
<append-ref ref="NetSendAppender"/>
<appender-ref ref="RollingFile"/>
</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提供了

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

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