• log4net学习笔记


    很多技术在项目中用过,但是都是别人封装或搭建好的,自己没有从头到尾梳理过;直接调用或者直接复制到其它项目,也没有发现啥问题,没有踩坑的经历很多东西都会被忽略,log4net就是其中之一。由于好久没有配置过Log4net了,差不多都遗忘了,最近就写了一个基于MVC的小demo从零开始试试log4net,也记录一下学习过程和遇到的问题。

    Log4net安装与配置

    1、创建项目后用nuget直接安装log4net

     

    2、log4net配置

    log4net配置可以直接写在系统配置文件中比如app.configweb.config,我为了方便修改和展示,也为了以后方便复用,就抽出来自定义一个配置文件log4net.config

    Log4net 有四种主要的组件,分别是Logger(记录器)、Repository(库)、Appender(附着器)以及Layout(布局)。

    先放上log4net.config配置文件代码。

    注:root节点的配置根据实际情况处理,否则可能会遇到无法写入日志或者重复写入日志问题

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <!--<configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>-->
      <!-- Level的级别,由高到低 -->
      <!-- OFF > Fatal > ERROR > WARN > DEBUG > INFO > ALL-->
      <!-- 解释:如果level是ERROR,则在cs文件里面调用log4net的info()方法,则不会写入到日志文件中-->
      <log4net>
        <!--根记录器,所有Logger都默认继承它
        如果没有定义根记录器,调用GetLogger没有找到定义的Logger时不会在日志文件写入日志
        -->
        <root>
          <level value="ALL" />
          <!--错误日志附着器引用
          由于所有记录器都默认继承root,所以此附着器引用对所有的记录器都生效,因此如下配置的情况,调用错误日志记录器时会记录2次错误日志
          -->
          <appender-ref ref="ErrorAppender" />
          <!--<appender-ref ref="ADONetAppender" />-->
        </root>
        <!--错误日志记录器-->
        <logger name="logerror">
          <level value="ALL" />
          <!--定义记录的日志级别-->
          <appender-ref ref="ErrorAppender" />
          <!--记录到哪个介质中去-->
        </logger>
        <!--信息日志记录器-->
        <logger name="loginfo">
          <level value="ALL" />
          <appender-ref ref="InfoAppender" />
          <appender-ref ref="ADONetAppender" />
        </logger>
        <!--错误日志附着器-->
        <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
          <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
          <param name="File" value="Log\LogError\" />
          <!--日志输出到exe程序这个相对目录下-->
          <param name="AppendToFile" value="true" />
          <!--输出的日志不会覆盖以前的信息-->
          <param name="MaxSizeRollBackups" value="100" />
          <!--备份文件的个数-->
          <param name="MaxFileSize" value="10240" />
          <!--当个日志文件的最大大小-->
          <param name="StaticLogFileName" value="false" />
          <!--是否使用静态文件名-->
          <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
          <!--日志文件名-->
          <param name="RollingStyle" value="Date" />
          <!--文件创建的方式,这里是以Date方式创建-->
          <!--错误日志布局-->
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%d [%t] %-5p %c %n%m%n" />
          </layout>
        </appender>
        <!--信息日志附着器-->
        <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件路径-->
          <param name="File" value="Log\LogInfo\" />
          <!--所有新的日志都进行追加-->
          <param name="AppendToFile" value="true" />
          <param name="MaxFileSize" value="10240" />
          <param name="MaxSizeRollBackups" value="100" />
          <!--文件名称不固定,可变-->
          <param name="StaticLogFileName" value="false" />
          <!--文件名称格式-->
          <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
          <!--文件名按日期滚动-->
          <param name="RollingStyle" value="Date" />
          <!--信息日志布局-->
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%d [%t] %-5p %c %n%m%n" />
          </layout>
        </appender>
        <!--数据库日志附着器-->
        <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net">
          <!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库-->
          <bufferSize value="1" />
          <!--或写为<param name="BufferSize" value="1" />-->
          <!--引用-->
          <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <!--连接数据库字符串-->
          <connectionString value="data source=.;database=Test2;user id=sa;password=123456;Enlist=true;Pooling=true;Max Pool Size = 512;" />
          <!--插入到表Log-->
          <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Location],[Exception]) VALUES (@log_date,@thread, @log_level, @logger,@message,@location,@exception)" />
          <!--日志记录时间,RawTimeStampLayout为默认的时间输出格式 -->
          <parameter>
            <parameterName value="@log_date" />
            <dbType value="DateTime" />
            <layout type="log4net.Layout.RawTimeStampLayout" />
          </parameter>
          <parameter>
            <parameterName value="@thread" />
            <dbType value="String" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%thread" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@Logger" />
            <dbType value="String" />
            <size value="100" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%logger" />
            </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="@message" />
            <dbType value="String" />
            <size value="100" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%message" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@location" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%location" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@exception" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%exception" />
            </layout>
          </parameter>
        </appender>
      </log4net>
      
      <!--log4net调式相关配置 需要放到web.config中才会生效  start-->
      <appSettings>
        <!--开启log4net调式-->
        <add key="log4net.Internal.Debug" value="true"/>
      </appSettings>
      <!--log4net调式监听-->
      <system.diagnostics>
        <trace autoflush="true">
          <listeners>
            <add name="textWriterTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Log\log4net.txt" />
          </listeners>
        </trace>
      </system.diagnostics>
      <!--log4net调式相关配置 需要放到web.config中  end-->
      <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
      </system.web>
    
    </configuration>

    可以看到主要包括2个节点configSectionslog4net

    1)configSections节点是对log4net配置节点的声明,如果没有这个节点会如下报错:

    无法读取配置节“log4net”,因为它缺少节声明

    注:如果log4net的配置放在自定义的配置文件里,这个声明是可以省略的

    2)所有关于log4net的配置都包含在log4net节点中。(要重点注意root(根记录器)和logger(记录器)之间的关联关系)

    3、关联log4net的配置文件

    需要在2cs文件中指定log4net的配置文件,分别是AssemblyInfo.csGlobal.asax.cs

    1) AssemblyInfo.cs

    如果是系统配置web.config,加入以下代码,也可以按自定义配置文件的方式处理。

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

    自定义配置文件需指定具体文件名,加入以下代码

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

    2) Global.asax.cs

    在全局文件中加入以下代码

    注:如果在AssemblyInfo.cs中指定了配置文件且文件放在根目录下,以下代码是可以省略的

    //配置log4
    log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Server.MapPath("~/log4net.config")));

    4、测试写入日志

    做好以上3个步骤后,就可以开始测试写入日志了,写入日志分为2个步骤

    1、首先通过GetLogger方法获取Logger(记录器),方法参数为记录器的名称.

    2、调用记录器各级别方法写入日志

    获取记录器有如下2种情况:

    1、传入配置文件中定义好的记录器名称获取记录器,代码如下:

    private ILog logError = LogManager.GetLogger("logerror");

    2、也可以传入相关调用处的类名,3中方式任选其一,代码如下:

    注:如果是使用这种方式,就一定要配置root根记录器,否则你会发现只创建了空的日志文件,没有往日志文件中写入日志

    private ILog log = LogManager.GetLogger("DefaultController");
    
    private ILog log = LogManager.GetLogger(typeof(DefaultController));
    
    private ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

     

     

     

    从日志文件中可以看到,”测试错误记录器”这个日志写入了2次。这是因为我们定义了root根记录器和logerror记录器,而且所有记录器默认都继承root,所以当我们调用logerror记录器时相当于是logerror+root的效果,从下面的代码中可以看到,root和logerror都引用了ErrorAppender附着器,所以写入了2次日志。

    如果不定义root根记录器,你用类名GetLogger获取记录器时会发现无法写入日志。

        <root>
    
          <level value="ALL" />
    
          <!--错误日志附着器引用
    
          由于所有记录器都默认继承root,所以此附着器引用对所有的记录器都生效,因此如下配置的情况,调用错误日志记录器时会记录2次错误日志
    
          -->
    
          <appender-ref ref="ErrorAppender" />
    
          <!--<appender-ref ref="ADONetAppender" />-->
    
        </root>
    
        <!--错误日志记录器-->
    
        <logger name="logerror">
    
          <level value="ALL" />
    
          <!--定义记录的日志级别-->
    
          <appender-ref ref="ErrorAppender" />
    
          <!--附着器引用-->
    
        </logger>

    到此处就完成了log4net配置,并成功写入了日志,下面再简单说下配置文件里各节点的关系。

    log4net节点介绍

    从配置文件中可以看到,我们主要用了3种节点root(根记录器)、logger(记录器)、appender(附着器)。

    从数量上看,我们只定义了1root节点、2logger节点(错误日志记录器、信息日志记录器),3appender节点(错误日志附着器、信息日志附着器、数据库日志附着器),这让我们知道我们可以定义多个logger记录器、多个appender附着器。

    logger记录器

    我们再看loginfo记录器,包含2种节点level(日志级别)appender-ref(附着器引用)

    其中Level的级别,由高到低OFF> Fatal > ERROR > WARN > DEBUG > INFO > ALL,大于等于你配置级别的日志才能写入,比如你level节点value配置成DEBUG,则INFO级别日志不会写入。

    appender-ref节点则表示附着器引用,一个记录器可以引用多个附着器,我们上面loginfo记录器就配置了写入日志文件,同时也写入数据库。

    appender附着器

    最后我们再看看数据库日志附着器ADONetAppender,里面有用到layout布局来获取插入数据库各字段的值,我们用的都是log4net自带的布局PatternLayout,能获取到一些常用信息,比如记录器名称%logger、信息%message,如果你要使用一些自定义字段,需要自己在代码中自定义布局,可参考Log4Net写入到数据库配置过程中的一些小问题备忘。常用信息如下所示:

    %mmessage)输出日志消息

    %nnewline)换行

    %ddatetime)输出当前语句运行的时刻

    %rruntime)输出当前语句的运行时刻

    %tthread id)当前语句所在的线程ID

    %ppriority)日志的当前优先级别,DEBUG INFO ……

    %cclass)当前日志对象的名称

    %L 输出语句所在的行号

    %F 输出语句所在的文件名

    %-数字 表示该项的最小长度,如果不够,用空格填充

    ADONetAppender节点下commandText节点是配置插入语句,需要在数据库中建好对应的表,数据库字段可以多于插入语句中的字段,但是不能少。创建表的语句:

    CREATE TABLE [dbo].[Log](
    
    [ID] [int] IDENTITY(1,1) NOT NULL,
    
    [Date] [datetime] NOT NULL,
    
    [Thread] [varchar](100) NULL,
    
    [Level] [varchar](100) NULL,
    
    [Logger] [varchar](200) NULL,
    
    [Message] [text] NULL,
    
    [Location] [text] NULL,
    
    [Exception] [text] NULL
    
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
    GO

    对于插入数据库相关附着器的配置,也可以直接查看binlog4net.xml文件,这个文件是安装log4net包后在bin下生成的,提供了一个sql  server相关附着器的例子,可以直接复制这个附着器,也能节省一点找资料的时间

     

     

    log4net调试

    最后再提一下log4net调试,当log4net出问题时可以看看里面记录的信息,如配置文件读取不到、记录器无法创建等等一些简单问题还是可以从中获取到的,至少比出问题时一脸蒙,无从下手要强。

    需要在系统配置文件web.config中加入如下代码:

       <appSettings>
    
        <!--开启log4net调式-->
    
        <add key="log4net.Internal.Debug" value="true"/>
    
      </appSettings>
    
      <!--log4net调式监听-->
    
      <system.diagnostics>
    
        <trace autoflush="true">
    
          <listeners>
    
            <add name="textWriterTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Log\log4net.txt" />
    
          </listeners>
    
        </trace>
    
      </system.diagnostics>

     根据配置的路径查看log4net.txt文件,如下:

     

     

     

    参考:

    Log4net的配置学习与总结 

    非常完善的Log4net详细说明

    Log4Net写入到数据库配置过程中的一些小问题备忘

     

  • 相关阅读:
    HDU 3501 Calculation 2 ——Dirichlet积
    BZOJ 1101 [POI2007]Zap ——Dirichlet积
    BZOJ 1257 [CQOI2007]余数之和sum ——Dirichlet积
    SGU 194 Reactor Cooling ——网络流
    BZOJ 1497 [NOI2006]最大获利 ——网络流
    BZOJ 2705 [SDOI2012]Longge的问题 ——Dirichlet积
    BZOJ 1653 [Usaco2006 Feb]Backward Digit Sums ——搜索
    BZOJ 1861 [Zjoi2006]Book 书架 ——Splay
    BZOJ 3130 [Sdoi2013]费用流 ——网络流
    BZOJ 3990 [SDOI2015]排序 ——搜索
  • 原文地址:https://www.cnblogs.com/hsybs/p/15129091.html
Copyright © 2020-2023  润新知