Walden1024

导航

[翻译]log4net教程

 

原文:log4net Tutorial

 

一、基础

  log4net分为三部分:配置、设置和调用。配置通常是在app.webconfig或web.config文件中;为了增加灵活性,我们也可以使用单独的配置文件。设置通常是几行代码,作用是设置和实例化一个logger连接。最后一部分是调用。

二、日志级别

  有7个日志级别,其中5个可以在代码中调用。下面是日志级别列表,按照优先级排列:

  1. OFF - nothing gets logged (cannot be called)
  2. FATAL
  3. ERROR
  4. WARN
  5. INFO
  6. DEBUG
  7. ALL - everything gets logged (cannot be called)

  这些级别会在代码和配置文件中多次使用。除了第一个和最后一个外,其他的级别没有指明代表什么含义。

三、配置

  在app.webconfig或web.config文件中配置log4net logger是标准做法。

1.Root

  我们需要一个root节点来覆盖最高级别的logger引用,这些是logger的继承信息。root节点唯一的其他作用就是定义日志的最低级别。因为所有logger均继承自root,因此低于指定级别的不会被记录为日志。这是控制程序中日志级别的简单方式,例如下面的例子中使用默认的INFO级别(这样DEBUG消息将会被忽略),并且应该启用root下面的两个appender的引用:

<root>
  <level value="INFO"/>
  <appender-ref ref="FileAppender"/>
  <appender-ref ref="ConsoleAppender" />
</root>

2.Additional Logger

  有时我们希望知道程序特定一部分的更多信息。log4net允许我们在root logger之外指定额外的logger。例如,下面的例子中指定了一个额外的logger,记录在OtherClass类对象内的控制台日志:

<logger name="Log4NetTest.OtherClass">
  <level value="DEBUG"/>
  <appender-ref ref="ConsoleAppender"/>
</logger>

  需要注意的是logger name的值为包含命名空间的类名。如果我们想要监控整个命名空间,就只要使用需要监控的命名空间填充即可。我(作者)建议不要在多个logger中重复使用日志输出目的地。我们可以这样做,但会有一些 不可预知的结果。

3.CofigSections

  在一个配置文件中除了log4net外通常还会有其他配置信息,我们需要定义一个节点来标识log4net配置的位置。下面的例子,表示log4net的配置信息在“log4net”标签下面:

<configSections>
  <section name="log4net" 
    type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>

4.通用的Appender

  appender是记录信息的名字。它用来指定信息被记录在哪里,怎样被记录以及在什么情况下被记录。虽然每个appender都有不同的参数来确定信息被记录在哪里,但是还是有一些通用的元素。第一个是name和type。必须为每个appender命名,并为他分配一个类型。例如:

<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">

4.1.Layout:

  在每个appender内部必须有一个layout节点。尽管根据不同的appender类型会有不同,但是基础的是相同的。我们需要一个类型来指定数据如何被写入。有多个选项,但是我(作者)推荐的是使用模式布局(pattern layout)类型。因为这样允许我们指定数据如何被写入数据存储。如果我们指定模式布局类型,我们还需要一个子标签来指定转换模式(conversion pattern)。我们的数据使用这种模式写入的到数据存储。例如:

<layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%ndc] 
    - %message%newline"/>
    </layout>

4.2.Conversion Pattern:

  正如上面提到的,转换模式实体是模式布局用来告诉appender如何存储信息的。在这些模式中可以使用很多不同的关键词和字符串。在这里列出我(作者)认为最有用和最重要的。所有的可以可以查看log4net文档:

  • %date - 使用本地时区信息输出日期。也可以使用花括号和布局模式格式化日期,例如%date{MMMM DD,yyyy HH:mm:ss,fff}会输出"January 01,2011 14:15:43,767"。但是建议使用log4net的日期格式(ABSOLUTE,DATE或ISO8601)这样性能会比较好。
  • %utcdate - 与%date相同,只是它输出世界时。
  • %exception - 如果传递过来一个异常,它将会被使用,并在异常信息后插入新的一行。如果没有异常传递过来,这个实体会被忽略并且不会产生新的一行。这个转换模式通常放在日志实体的最后,并且在异常前面通常也会插入一行。
  • %level - 这是我们指定的事件级别(DEBUG,INFO,WARN等)。
  • %message - 我们传递到日志事件的消息。
  • %newline - 这是新行实体。根据我们程序的平台翻译成新行字符。这是换行的首选方法,并且相对于特定的平台供应商没有性能问题。
  • %timestamp - 程序运行以来的毫秒数。
  • %thread - 实体产生的线程名(如果线程没有命名则是线程的编号)。

  下面几个也非常有用,但是使用时要特别注意,因为它们会对性能造成影响:

  • %identity - 使用Principal.Identity.Name方法获取的当前用户的用户名。
  • %location - 在调试时特别有用,它将告诉我们日志方法是否被调用(行号、方法等)。然而 ,在Release模式下信息的数量将会减少,这取决于系统访问编译后的代码。
  • %line - 代码的行号(即上面location的行号)。
  • %method - 调用日志实体的方法(即上面location的方法)。
  • %username - 输出WindowsIdentity属性的值。

  有些配置文件使用的是字母而不是名字。这有利于整个实体。我(作者)在这里不会深度介绍,我们只要知道这些实体可以被格式化为合适的宽度。可以在两边添加空格,也可以将值截断来适应内部固定宽度的列。基本的语法是将数字或值放在%号和名字之间:

  • X - 指定了字符的最小长度。如果字符的长度小于此值,将会在左侧填充空格。例如,%10message将会输出" hi"。
  • -X - 和上面相同,不同的是在右侧填充空格。例如,%-10message将会输出"hi "。
  • .X - 指定字符的最大长度。如果超出长度将会从左侧开始截取。例如,%.10message如果字符串为"Error entry"将会输出"rror entry"。

  我们可以将上面的组合使用,例如"%10.20message",如果长度不足10则在左侧填充空格,如果超过20将会截取。

4.3.Filter:

  Filter是appender的一部分。使用filter我们可以指定哪个(或哪些)级别被记录,甚至可以在消息中寻找关键字。Filter可以混合和匹配,当时当我们这样做的时候要特别注意。当消息符合filter的内部标准,它将会被记录并且filter的过程结束。这是Filter最大的缺陷,因此当我们处理复杂的filter时,filter的排序就变得非常重要。

4.3.1.StringMatchFilter:

  字符串匹配filter在被记录的信息中寻找指定的字符串。我们可以知道多个字符串匹配filter。它们在一个查询语句中类似OR组合。需要注意的是不要试图匹配一个指定的字符串不排除一个实体(因为它可以继续下一个字符串匹配filter)。这意味着,我们可能会遇到没有匹配的情况。这种情况下,默认的行为是记录这个实体。因此,在字符串匹配filter设置的最后,包含一个否认所有filter(下面会介绍)在没有匹配时组织实体被记录是非常必要的。下面是字符串匹配filter的例子:

<filter type="log4net.Filter.StringMatchFilter">
  <stringToMatch value="test" />
</filter>

4.3.2.LevelRangeFilter:

  级别范围filter告诉系统只有在指定范围内的实体才会被记录。下面的例子中INFO、WARN、ERROR级别的事件会被记录,但是DEBUG事件不会被记录。我们在这个实体后面不需要定义否认所有filter,因为否定所有filter是默认的。

<filter type="log4net.Filter.LevelRangeFilter">
  <levelMin value="INFO" />
  <levelMax value="FATAL" />
</filter>

4.3.3.LevelMatchFilter:

  级别匹配filter与级别范围filter类似,不同的是它只捕获指定的一种级别。它没有默认的否定所有filter,因此要在级别匹配filter之后添加否定所有filter。

<filter type="log4net.Filter.LevelMatchFilter">
  <levelToMatch value="ERROR"/>
</filter>

4.3.4.DenyAllFilter:

  如果被忘记,appender通常不会按照所期望的工作。指定这个条目的唯一目的是指定不产生日志实体。如果只定义了这个条目,将不会有日志产生。

<filter type="log4net.Filter.DenyAllFilter" />

5.Appender

  每个类型的appender都有它自己的语法定义数据存储到哪里。最不寻常的是把日志存储到数据库。

5.1.Console Appender:

  我(作者)通常使用这个appender来测试,但是它在产品上同样有用。它写入到输出窗口,如果我们使用的是console程序它会写入到命令窗口。下面的filter输出的值类似"2010-12-26 15:41:03,581 [10] WARN Log4NetTest.frmMain - This is a WARN test.",在它的末尾将会换行。

<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date{ABSOLUTE} 
    [%thread] %level %logger - %message%newline"/>
  </layout>
  <filter type="log4net.Filter.StringMatchFilter">
    <stringToMatch value="test" />
  </filter>
  <filter type="log4net.Filter.DenyAllFilter" />
</appender>

5.2.File Appender:

  这个appender将会写入一个文本文件。该appender必须指定文件名(下面的例子中文件名为mylogfile.txt,将会存储在与可执行文件相同的路径),我们指定在文件末尾添加(而不是覆盖),并且指定FileAppender使用最小锁这样该文件可以被多个appender使用。

<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="mylogfile.txt" />
  <appendToFile value="true" />
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="INFO" />
    <levelMax value="FATAL" />
  </filter>
</appender>

5.3.Rolling File Appender:

  应该尽量使用该Appender代替file appender。Rolling file appender的目的是与file appender执行相同的功能,但是每个文件只存储一定量的数据。这样就不用担心日志耗尽存储空间。如果没有使用滚动选项,在足够时间的情况下,即使是一个小的应用程序也会耗尽存储空间。在下面的例子中使用于上面例子类似的方式记录日志,但是指定了每个文件的大小为10MB,并且在删除之前有5个存档文件(从最之前的文件开始删除)。存档文件具有相同的名字,只是在每个文件名字后添加一个点和数组(例如,第二个存档的文件名为mylogfile.txt.2).staticLogFileName确保日志文件与指定的文件名相同(本例中为mylogfile.txt)。

<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
  <file value="mylogfile.txt" />
  <appendToFile value="true" />
  <rollingStyle value="Size" />
  <maxSizeRollBackups value="5" />
  <maximumFileSize value="10MB" />
  <staticLogFileName value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
  </layout>
</appender>

5.4.ADO.NET Appender:

  下面的例子是写入SQL Server数据库,但是我们可以使用这种模式写入任意数据库。

  注意:如果我们发现ADO.NET appender没有反应,查看bufferSize的值。这个值定义的是将日志写入数据库之前log4
net缓存的语句数量。

  更多信息请参考:http://logging.apache.org/log4net/release/config-examples.html

<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
  <bufferSize value="100" />
  <connectionType value="System.Data.SqlClient.SqlConnection, 
   System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <connectionString value="data source=[database server];
    initial catalog=[database name];integrated security=false;
    persist security info=True;User ID=[user];Password=[password]" />
  <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],
    [Message],[Exception]) VALUES (@log_date, @thread, @log_level, 
    @logger, @message, @exception)" />
  <parameter>
    <parameterName value="@log_date" />
    <dbType value="DateTime" />
    <layout type="log4net.Layout.RawTimeStampLayout" />
  </parameter>
  <parameter>
    <parameterName value="@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="@logger" />
    <dbType value="String" />
    <size value="255" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%logger" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@message" />
    <dbType value="String" />
    <size value="4000" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%message" />
    </layout>
  </parameter>
  <parameter>
    <parameterName value="@exception" />
    <dbType value="String" />
    <size value="2000" />
    <layout type="log4net.Layout.ExceptionLayout" />
  </parameter>
</appender>

四、代码

  在我们的程序中引入log4net的dll时,有三行代码是我们需要知道的。第一个是需要一次性放置在我们的类中。我(作者)通常它放在Program.cs文件的using语句下面:

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

  第二个是需要在每个类中用到的,定义一个变量用来调用log4net的方法。它使用System.Reflection调用后去当前类的信息:

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

  最后的代码块是实际调用来记录一些信息。例如:

log.Info("Info logging");

  注意,我们可以在后面添加一个可选参数包含异常信息。与下面的非常类似:

log.Error("This is my error", ex);

  ex是异常对象。我们需要使用%exception来捕获异常信息。

五、记录额外的数据

  通常使用log4net的基本配置就可以为应用程序提供足够的信息。但是,有时我们想要使用标准方法记录更多的信息。例如,在ADO.NET appender中,我们可能想要添加用户名字段而不仅仅是信息字段。没有一种转换模式与应用程序中的用户名匹配。然而,我们可以使用上下文属性来自定义可以被appender访问的属性。例如:

log4net.GlobalContext.Properties["testProperty"] = "This is my test property information";

  需要注意几点:1.自定义属性可以任意命名,但是如果命名与已经存在的命名相同,将会把原来的覆盖。2.本例中使用的是Global上下文,但是有四个上下文可以被利用。它们是基于线程的。Global定义的可以应用在程序进程、逻辑继承和进一步限制时间范围的任何地方。如果两个属性具有相同的名字,将会取窄范围的那个的值。

  捕获自定义属性的例子:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date{ABSOLUTE} [%thread] %level 
                            %logger - %message%newlineExtra Info: %property{
                            testProperty}%newline%exception"/>
</layout>

  更多信息请查看:http://logging.apache.org/log4net/release/manual/contexts.html

六、不使用app.config/web.config

  有时我们需要单独的文件存储log4net的配置信息。实际上这是存储配置信息最好的方法,因为我们可以有不同的配置副本应用于项目。这可以减少开发时间并且允许我们记录标准化的日志信息。如果要单独存储配置文件,我们需要更改程序的两个地方。第一件是将配置文件保存在另一个文件。第二件是修改调用设置,例如:

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

  还可以使用另一种方法,这种方法需要把配置文件命名为程序集名称(包括扩展名):

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

  在上面的例子中如果我们的程序是test.exe,log4net的配置文件需要命名为test.exe.mylogger。

七、配置文件模板

<!--This is the root of your config file-->
<configuration> <!-- Level 0 -->
  <!--This specifies what the section name is-->
  <configSections> <!-- Level 1 -->
    <section name="log4net" 
      type="log4net.Config.Log4NetConfigurationSectionHandler, 
            log4net"/> <!-- Level 2 -->
  </configSections>
  <log4net> <!-- Level 1 -->
    <appender>  <!-- Level 2 -->
      <layout>  <!-- Level 3 -->
        <conversionPattern />  <!-- Level 4 -->
      </layout>
      <filter>  <!-- Level 3 -->
      </filter>
    </appender>
    <root> <!-- Level 2 -->
      <level /> <!-- Level 3 -->
      <appender-ref /> <!-- Level 3 -->
    </root>
    <logger> <!-- Level 2 -->
      <level /> <!-- Level 3 -->
      <appender-ref /> <!-- Level 3 -->
    </logger>
  </log4net>
</configuration>

 

  发现已经有园友翻译过这篇文章,而且比我翻译的好很多:Log4Net指南

 

posted on 2015-07-02 17:40  Walden1024  阅读(292)  评论(0编辑  收藏  举报