Apache logging services logo

Apache log4net™ 手册 - 配置

配置

将日志请求插入应用程序代码需要大量的计划和努力。观察表明,大约 4% 的代码用于日志记录。因此,即使是中等规模的应用程序也会在其代码中嵌入数千条日志语句。鉴于其数量,在无需手动修改的情况下管理这些日志语句变得势在必行。

log4net 环境可以通过编程方式完全配置。但是,使用配置文件配置 log4net 更加灵活。目前,配置文件是用 XML 编写的。

让我们借助一个使用 log4net 的假想应用程序 MyApp 来了解一下它是如何实现的。

using Com.Foo;

// Import log4net classes.
using log4net;
using log4net.Config;

public class MyApp 
{
    // Define a static logger variable so that it references the
    // Logger instance named "MyApp".
    private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

    static void Main(string[] args) 
    {
        // Set up a simple configuration that logs on the console.
        BasicConfigurator.Configure();

        log.Info("Entering application.");
        Bar bar = new Bar();
        bar.DoIt();
        log.Info("Exiting application.");
    }
}

MyApp 首先导入与 log4net 相关的类。然后,它定义了一个名为 MyApp 的静态日志记录器变量,该变量恰好是该类的完全限定名。

MyApp 使用以下 Bar

// Import log4net classes.
using log4net;

namespace Com.Foo
{
    public class Bar 
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Bar));

        public void DoIt()
        {
            log.Debug("Did it again!");
        }
    }
}

调用 BasicConfigurator.Configure() 方法会创建一个相当简单的 log4net 设置。此方法硬编码为向日志记录器添加一个 ConsoleAppender。输出将使用设置为模式 "%-4timestamp [%thread] %-5level %logger %ndc - %message%newline"PatternLayout 进行格式化。

请注意,默认情况下,日志记录器被分配为 Level.DEBUG

MyApp 的输出为

0    [main] INFO  MyApp  - Entering application.
36   [main] DEBUG Com.Foo.Bar  - Did it again!
51   [main] INFO  MyApp  - Exiting application.

作为旁注,让我提一下,在 log4net 中,子日志记录器仅链接到其现有的祖先。特别是,名为 Com.Foo.Bar 的日志记录器直接链接到日志记录器,从而绕过了未使用的 ComCom.Foo 日志记录器。这显着提高了性能并减少了 log4net 的内存占用。

MyApp 类通过调用 BasicConfigurator.Configure() 方法来配置 log4net。其他类只需要导入 log4net 命名空间,检索它们想要使用的日志记录器,然后进行日志记录。

前面的示例始终输出相同的日志信息。幸运的是,很容易修改 MyApp,以便可以在运行时控制日志输出。以下是一个略微修改后的版本。

using Com.Foo;

// Import log4net classes.
using log4net;
using log4net.Config;

public class MyApp 
{
    private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));

    static void Main(string[] args) 
    {
        // BasicConfigurator replaced with XmlConfigurator.
        XmlConfigurator.Configure(new System.IO.FileInfo(args[0]));

        log.Info("Entering application.");
        Bar bar = new Bar();
        bar.DoIt();
        log.Info("Exiting application.");
    }
}

此版本的 MyApp 指示 XmlConfigurator 解析配置文件并相应地设置日志记录。配置文件的路径在命令行上指定。

以下是一个示例配置文件,它会产生与前面的基于 BasicConfigurator 的示例完全相同的输出。

<log4net>
    <!-- A1 is set to be a ConsoleAppender -->
    <appender name="A1" type="log4net.Appender.ConsoleAppender">

        <!-- A1 uses PatternLayout -->
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
        </layout>
    </appender>
    
    <!-- Set root logger level to DEBUG and its only appender to A1 -->
    <root>
        <level value="DEBUG" />
        <appender-ref ref="A1" />
    </root>
</log4net>

假设我们不再有兴趣查看属于 Com.Foo 包的任何组件的输出。以下配置文件展示了一种实现此目标的可能方法。

<log4net>
    <!-- A1 is set to be a ConsoleAppender -->
    <appender name="A1" type="log4net.Appender.ConsoleAppender">

        <!-- A1 uses PatternLayout -->
        <layout type="log4net.Layout.PatternLayout">
            <!-- Print the date in ISO 8601 format -->
            <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" />
        </layout>
    </appender>
    
    <!-- Set root logger level to DEBUG and its only appender to A1 -->
    <root>
        <level value="DEBUG" />
        <appender-ref ref="A1" />
    </root>
    
    <!-- Print only messages of level WARN or above in the package Com.Foo -->
    <logger name="Com.Foo">
        <level value="WARN" />
    </logger>
</log4net>

使用此文件配置的 MyApp 的输出如下所示。

2000-09-07 14:07:41,508 [main] INFO  MyApp - Entering application.
2000-09-07 14:07:41,529 [main] INFO  MyApp - Exiting application.

由于日志记录器 Com.Foo.Bar 没有分配级别,因此它从 Com.Foo 继承其级别,该级别在配置文件中设置为 WARN。来自 Bar.DoIt 方法的日志语句的级别为 DEBUG,低于日志记录器级别 WARN。因此,DoIt() 方法的日志请求被抑制。

以下是一个使用多个附加器的示例配置文件。

<log4net>
    <appender name="Console" type="log4net.Appender.ConsoleAppender">
        <layout type="log4net.Layout.PatternLayout">
            <!-- Pattern to output the caller's file name and line number -->
            <conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
        </layout>
    </appender>
    
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
        <file value="example.log" />
        <appendToFile value="true" />
        <maximumFileSize value="100KB" />
        <maxSizeRollBackups value="2" />

        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%level %thread %logger - %message%newline" />
        </layout>
    </appender>
    
    <root>
        <level value="DEBUG" />
        <appender-ref ref="Console" />
        <appender-ref ref="RollingFile" />
    </root>
</log4net>

使用此配置文件调用增强的 MyApp 将在控制台上输出以下内容。

 INFO [main] (MyApp.cs:16) - Entering application.
DEBUG [main] (Bar.cs:12) - Doing it again!
 INFO [main] (MyApp.cs:19) - Exiting application.

此外,由于日志记录器已分配了第二个附加器,因此输出也将被定向到 example.log 文件。当此文件达到 100KB 时,它将被滚动。发生滚动时,example.log 的旧版本将自动移动到 example.log.1

请注意,为了获得这些不同的日志记录行为,我们不需要重新编译代码。我们可以轻松地将日志记录到电子邮件地址,将所有 Com.Foo 输出重定向到 NT 事件日志记录器,或将日志记录事件转发到远程 log4net 服务器,该服务器将根据本地服务器策略进行日志记录。

有关使用 XmlConfigurator 配置附加器的更多示例,请参阅 示例附加器配置 文档。

配置属性

log4net 配置可以使用程序集级属性进行配置,而不是以编程方式指定。

  • XmlConfiguratorAttribute

    log4net.Config.XmlConfiguratorAttribute 允许使用以下属性配置 XmlConfigurator

    • ConfigFile

      如果指定,这是要与 XmlConfigurator 一起使用的配置文件的名称。此文件路径相对于应用程序基目录 (AppDomain.CurrentDomain.BaseDirectory)。

      此属性不能与 ConfigFileExtension 属性一起使用。

    • ConfigFileExtension

      如果指定,这是配置文件的扩展名。程序集文件名用作基本名称,并附加此扩展名。例如,如果程序集从文件 TestApp.exe 加载,并且 ConfigFileExtension 属性设置为 log4net,则配置文件名为 TestApp.exe.log4net。这等效于将 ConfigFile 属性设置为 TestApp.exe.log4net

      配置文件的路径是通过使用应用程序基目录 (AppDomain.CurrentDomain.BaseDirectory)、程序集文件名和配置文件扩展名构建的。

      此属性不能与 ConfigFile 属性一起使用。

    • Watch

      如果指定此标志并将其设置为 true,则框架将监视配置文件,并在每次修改文件时重新加载配置。

    如果未指定 ConfigFileConfigFileExtension 属性,则应用程序配置文件(例如 TestApp.exe.config)将用作 log4net 配置文件。

    示例用法

    // Configure log4net using the .config file
    [assembly: log4net.Config.XmlConfigurator(Watch=true)]
    // This will cause log4net to look for a configuration file
    // called TestApp.exe.config in the application base
    // directory (i.e. the directory containing TestApp.exe)
    // The config file will be watched for changes.
                                
    // Configure log4net using the .log4net file
    [assembly: log4net.Config.XmlConfigurator(ConfigFileExtension="log4net",Watch=true)]
    // This will cause log4net to look for a configuration file
    // called TestApp.exe.log4net in the application base
    // directory (i.e. the directory containing TestApp.exe)
    // The config file will be watched for changes.
                                

    此属性每个程序集只能使用一次。

使用属性可以更清晰地定义应用程序的配置将从何处加载。但是,值得注意的是,属性纯粹是被动的。它们只是信息。因此,如果您使用配置属性,则必须调用 log4net 以允许它读取属性。对 LogManager.GetLogger 的简单调用将导致读取和处理调用程序集上的属性。因此,必须在应用程序启动期间尽早进行日志记录调用,并且肯定要在加载和调用任何外部程序集之前。

appSettings

如果您使用 属性 配置 log4net,则应用程序配置文件的appSettings部分的两个设置可用于覆盖程序集属性中给出的值。

键为 "log4net.Config" 的设置将覆盖配置文件名(并被认为相对于应用程序的基目录),键为 "log4net.Config.Watch" 的设置将确定是否应监视文件以进行更改。

即使程序集属性

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

将您的应用程序配置为使用配置文件 "TestApp.exe.config" 并且不监视它以进行更改,您也可以通过添加以下内容来覆盖它以使用文件 "log4net.config" 并监视它

<appSettings>
  <add key="log4net.Config" value="log4net.config"/>
  <add key="log4net.Config.Watch" value="True"/>
</appSettings>
                  

到您的应用程序配置文件中。

配置文件

通常,log4net 配置使用文件指定。此文件可以通过两种方式之一读取

  • 使用 .NET System.Configuration API
  • 直接读取文件内容

.config 文件

只有当配置数据位于应用程序的配置文件中时,System.Configuration API 才可用;名为MyApp.exe.configWeb.config 的文件。由于 System.Configuration API 不支持重新加载配置文件,因此无法使用 log4net.Config.XmlConfigurator.ConfigureAndWatch 方法监视配置设置。使用 System.Configuration API 读取配置数据的最大优点是,它需要的权限少于直接访问配置文件。

使用 System.Configuration API 配置应用程序的唯一方法是调用 log4net.Config.XmlConfigurator.Configure() 方法或 log4net.Config.XmlConfigurator.Configure(ILoggerRepository) 方法。

为了将配置数据嵌入 .config 文件中,必须使用 configSections 元素向 .NET 配置文件解析器标识节名称。该节必须指定将用于解析配置节的 log4net.Config.Log4NetConfigurationSectionHandler。此类型必须是完全限定的程序集,因为它是由 .NET 配置文件解析器加载的,而不是由 log4net 加载的。必须指定 log4net 程序集的正确程序集名称。以下是一个简单的示例配置文件,它指定了用于 log4net 节的正确节处理程序。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
            </layout>
        </appender>
        <root>
            <level value="INFO" />
            <appender-ref ref="ConsoleAppender" />
        </root>
    </log4net>
</configuration>

在上面的示例中,指定了 log4net 程序集。此程序集必须位于 .NET 运行时可以找到它的位置。例如,它可以位于与应用程序相同的目录中。如果 log4net 程序集存储在 GAC 中,则必须指定完全限定的程序集名称,包括区域性、版本和公钥。

使用 .config 文件指定配置时,节名称和 XML 元素名称必须为 log4net

直接读取文件

XmlConfigurator 可以直接读取任何 XML 文件并使用它来配置 log4net。这包括应用程序的 .config 文件;名为MyApp.exe.configWeb.config 的文件。不直接读取配置文件的唯一原因是,如果应用程序没有足够的权限读取文件,则必须使用 .NET 配置 API 加载配置(见上文)。

要读取配置的文件可以使用任何接受 System.IO.FileInfo 对象的 log4net.Config.XmlConfigurator 方法来指定。由于可以监控文件系统以获取文件更改通知,因此可以使用 ConfigureAndWatch 方法来监控配置文件的修改并自动重新配置 log4net。

此外,还可以使用 log4net.Config.XmlConfiguratorAttribute 来指定要读取配置的文件。

配置是从文件中的 log4net 元素读取的。文件中只能指定一个 log4net 元素,但它可以位于 XML 层次结构中的任何位置。例如,它可能是根元素

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
        </layout>
    </appender>
    <root>
        <level value="INFO" />
        <appender-ref ref="ConsoleAppender" />
    </root>
</log4net>

或者它可能嵌套在其他元素中

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
    </configSections>
    <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
            </layout>
        </appender>
        <root>
            <level value="INFO" />
            <appender-ref ref="ConsoleAppender" />
        </root>
    </log4net>
</configuration>

上面的示例展示了如何将配置数据嵌入到 .config 文件中,即使该文件是直接由 log4net 读取的。需要注意的是,如果 .NET 配置文件解析器发现没有使用 configSections 元素注册的元素,它将抛出异常。因此,在上面的示例中,注册了 log4net 节点名称,但指定用于处理该节点的类型是 System.Configuration.IgnoreSectionHandler。这是一个内置类,表示将使用另一种方法来读取配置节点。

配置语法

log4net 包含一个配置读取器,它解析 XML DOM,即 log4net.Config.XmlConfigurator。本节定义了配置器接受的语法。

这是一个有效的 XML 配置示例。根元素必须是 <log4net>。请注意,这并不意味着该元素不能嵌入到另一个 XML 文档中。有关如何在配置文件中嵌入 XmlConfigurator XML 的更多信息,请参见上面的 配置文件 部分。

<log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
        </layout>
    </appender>
    <root>
        <level value="INFO" />
        <appender-ref ref="ConsoleAppender" />
    </root>
</log4net>

<log4net> 元素支持以下属性

属性 描述
debug 可选属性。值必须是 truefalse。默认值为 false。将此属性设置为 true 以启用此配置的内部 log4net 调试。
update 可选属性。值必须是 MergeOverwrite。默认值为 Merge。将此属性设置为 Overwrite 以在应用此配置之前重置正在配置的存储库的配置。
threshold 可选属性。值必须是存储库中注册的级别的名称。默认值为 ALL。设置此属性以限制记录到整个存储库中的消息,而不管消息记录到的记录器是什么。

<log4net> 元素支持以下子元素

元素 描述
appender 允许零个或多个元素。定义一个追加器。
logger 允许零个或多个元素。定义记录器的配置。
renderer 允许零个或多个元素。定义一个对象渲染器。
root 可选元素,最多允许一个。定义根记录器的配置。
param 允许零个或多个元素。存储库特定的参数

追加器

追加器只能定义为 <log4net> 元素的子元素。每个追加器必须具有唯一的名称。必须指定追加器的实现类型。

此示例展示了如何定义类型为 log4net.Appender.ConsoleAppender 的追加器。追加器将被称为 ConsoleAppender

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

<appender> 元素支持以下属性

属性 描述
name 必需属性。值必须是此追加器的字符串名称。该名称在配置文件中定义的所有追加器中必须是唯一的。此名称由记录器的 <appender-ref> 元素用于引用追加器。
type 必需属性。值必须是此追加器的类型名称。如果追加器未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。

<appender> 元素支持以下子元素

元素 描述
appender-ref 允许零个或多个元素。允许追加器引用其他追加器。并非所有追加器都支持此功能。
filter 允许零个或多个元素。定义此追加器使用的过滤器。
layout 可选元素,最多允许一个。定义此追加器使用的布局。
param 允许零个或多个元素。追加器特定的参数。

有关配置追加器的示例,请参见 示例追加器配置 文档。

过滤器

过滤器元素只能定义为 <appender> 元素的子元素。

<filter> 元素支持以下属性

属性 描述
type 必需属性。值必须是此过滤器的类型名称。如果过滤器未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。

<filter> 元素支持以下子元素

元素 描述
param 允许零个或多个元素。过滤器特定的参数。

过滤器形成一个链,事件必须通过该链。链中的任何过滤器都可以接受事件并停止处理,拒绝事件并停止处理,或允许事件继续传递到下一个过滤器。如果事件到达过滤器链的末尾而没有被拒绝,则它将被隐式接受并被记录。

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

此过滤器将拒绝级别低于 INFO 或高于 FATAL 的事件。介于 INFOFATAL 之间的事件将被记录。

如果我们只想允许包含特定子字符串(例如 'database')的消息通过,则需要指定以下过滤器

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

第一个过滤器将在事件的消息文本中查找子字符串 'database'。如果找到该文本,则过滤器将接受该消息,并停止过滤器处理,该消息将被记录。如果未找到该子字符串,则事件将传递到下一个过滤器进行处理。如果没有下一个过滤器,则事件将被隐式接受并被记录。但由于我们不希望不匹配的事件被记录,因此我们需要使用一个 log4net.Filter.DenyAllFilter,它只拒绝到达它的所有事件。此过滤器仅在过滤器链的末尾有用。

如果我们想允许消息文本中包含 'database' 或 'ldap' 的事件,我们可以使用以下过滤器

<filter type="log4net.Filter.StringMatchFilter">
    <stringToMatch value="database"/>
</filter>
<filter type="log4net.Filter.StringMatchFilter">
    <stringToMatch value="ldap"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />

布局

布局元素只能定义为 <appender> 元素的子元素。

<layout> 元素支持以下属性

属性 描述
type 必需属性。值必须是此布局的类型名称。如果布局未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。

<layout> 元素支持以下子元素

元素 描述
param 允许零个或多个元素。布局特定的参数。

此示例展示了如何配置使用 log4net.Layout.PatternLayout 的布局。

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

根记录器

只能定义一个根记录器元素,它必须是 <log4net> 元素的子元素。根记录器是记录器层次结构的根。所有记录器最终都继承自此记录器。

一个示例根记录器

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

<root> 元素不支持任何属性。

<root> 元素支持以下子元素

元素 描述
appender-ref 允许零个或多个元素。允许记录器按名称引用追加器。
level 可选元素,最多允许一个。定义此记录器的记录级别。此记录器只接受此级别或更高级别的事件。
param 允许零个或多个元素。记录器特定的参数。

记录器

记录器元素只能定义为 <log4net> 元素的子元素。

一个示例记录器

<logger name="LoggerName">
    <level value="DEBUG" />
    <appender-ref ref="ConsoleAppender" />
</logger>

<logger> 元素支持以下属性。

属性 描述
name 必需属性。值必须是记录器的名称。
additivity 可选属性。值可以是 truefalse。默认值为 true。将此属性设置为 false 以阻止此记录器继承在父记录器上定义的追加器。

<logger> 元素支持以下子元素

元素 描述
appender-ref 允许零个或多个元素。允许记录器按名称引用追加器。
level 可选元素,最多允许一个。定义此记录器的记录级别。此记录器只接受此级别或更高级别的事件。
param 允许零个或多个元素。记录器特定的参数。

渲染器

渲染器元素只能定义为 <log4net> 元素的子元素。

一个示例渲染器

<renderer renderingClass="MyClass.MyRenderer" renderedClass="MyClass.MyFunkyObject" />

<renderer> 元素支持以下属性。

属性 描述
renderingClass 必需属性。值必须是此渲染器的类型名称。如果该类型未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。这是将负责渲染 renderedClass 的对象的类型。
renderedClass 必需属性。值必须是此渲染器的目标类型的类型名称。如果该类型未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。这是此渲染器将渲染的类型的名称。

<renderer> 元素不支持任何子元素。

参数

参数元素可以是许多元素的子元素。有关详细信息,请参见上面的特定元素。

一个示例 param

<param name="ConversionPattern" value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />

<param> 元素支持以下属性。

属性 描述
name 必需属性。值必须是要在父对象上设置的参数的名称。
value 可选属性。必须指定 valuetype 属性之一。此属性的值是一个字符串,可以转换为参数的值。
type 可选属性。必须指定 valuetype 属性之一。此属性的值是一个类型名称,用于创建并设置为参数的值。如果该类型未在 log4net 程序集中定义,则此类型名称必须是完全限定的程序集名称。

<param> 元素支持以下子元素

元素 描述
param 允许零个或多个元素。参数特定的参数。

一个使用嵌套 param 元素的示例 param

<param name="evaluator" type="log4net.spi.LevelEvaluator">
    <param name="Threshold" value="WARN"/>
<param>

扩展参数

配置参数直接映射到对象上的可写属性。可用的属性取决于正在配置的实际对象的类型。log4net SDK 文档包含 log4net 程序集中包含的所有组件的 API 参考。

对于第三方组件,请参见其相关的 API 参考,了解可用的属性的详细信息。

紧凑参数语法

所有参数都可以选择使用参数名称作为元素名称来指定,而不是使用 param 元素和 name 属性。

例如,一个 param

<param name="evaluator" type="log4net.spi.LevelEvaluator">
    <param name="Threshold" value="WARN"/>
<param>

可以写成

<evaluator type="log4net.spi.LevelEvaluator">
    <threshold value="WARN"/>
<evaluator>