如何在使用共享程序集时配置log4net?

时间:2013-09-15 15:57:33

标签: log4net log4net-configuration

如何在使用共享程序集时配置log4net?

我有多个依赖于通用组件的组件。每个组件都在自己的组件中。所有组件都使用log4net进行日志记录。所有组件都加载到单个进程空间中,但组件的使用顺序各不相同。所有外接组件在首次使用时加载其各自的log4net配置,以尝试将日志记录数据发送到它们。公共组件不加载任何配置。另外,存在不使用公共组件的遗留组件。它还在首次使用时输出并加载其配置。我无法直接触及此旧组件的代码或配置。

我面临的问题是,由于组件在首次使用时加载了配置,因此最后一个加载配置的人获胜。这会导致日志记录发生,但所有日志输出最终都会进入最后加载的配置。显然,查看日志文件并将其他组件的日志条目写入其中是非常难看的。

我使用RepositoryAttribute和AliasRepositoryAttribute找到了部分解决方案。让外部组件将其配置加载到其“记录器存储库”中,并有效地将它们彼此隔离。遗留组件现在可以愉快地写入自己的日志,而不会产生组件的噪音,我的组件很乐意写入自己的日志,而不会在其他日志中产生噪音。

我说部分解决方案因为仍然存在针对公共组件进行日志记录的情况。使用AliasRepositoryAttribute时,加载的第一个组件和公共组件的别名将获得所有日志输出,即使它是另一个调用公共组件的组件。这很糟糕,因为我将丢失后面组件中的重要日志记录信息,并且我将在第一个日志中包含不相关的日志记录信息。

以下代码演示了此问题:

常见:(代表共同的组成部分)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Config;
[assembly: Repository("CommonLib")]

namespace CommonLib
{
    public class CommonClass
    {
        static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public void DoCommon(string from)
        {
            Log.Debug("DoCommon:" + from);
        }
    }
}

图书馆A :(代表其中一个外接组件)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using CommonLib;
using log4net;
using log4net.Config;
[assembly: Repository("ALib")]
[assembly: AliasRepository("CommonLib")]

namespace ALib
{
    public static class LogPrep
    {
        static bool _loaded = false;

        public static void Ensure()
        {
            if (_loaded)
                return;

            var doc = new XmlDocument();
            doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
         xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         debug='true'>
  <appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
    <mapping>
        <level value='DEBUG' />
        <foreColor value='White' />
        <backColor value='Green' />
    </mapping>
    <layout type='log4net.Layout.PatternLayout'>
      <conversionPattern value='ALib: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
    </layout>
  </appender>
  <root>
    <level value='DEBUG' />
    <appender-ref ref='ConsoleAppender' />
  </root>
</log4net>");
            XmlConfigurator.Configure(doc.DocumentElement);

            _loaded = true;
        }
    }

    public class AClass
    {
        static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public void DoA()
        {
            LogPrep.Ensure();
            Log.Debug("DoA");

            var common = new CommonClass();
            common.DoCommon("A");
        }
    }
}

图书馆B :(代表另一个外接组件)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using CommonLib;
using log4net;
using log4net.Config;
[assembly: Repository("BLib")]
[assembly: AliasRepository("CommonLib")]

namespace BLib
{
    public class BClass
    {
        static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static class LogPrep
        {
            static bool _loaded = false;

            public static void Ensure()
            {
                if (_loaded)
                    return;

                var doc = new XmlDocument();
                doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
         xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         debug='true'>
  <appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
    <mapping>
        <level value='DEBUG' />
        <foreColor value='White' />
        <backColor value='Red' />
    </mapping>
    <layout type='log4net.Layout.PatternLayout'>
      <conversionPattern value='BLib: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
    </layout>
  </appender>
  <root>
    <level value='DEBUG' />
    <appender-ref ref='ConsoleAppender' />
  </root>
</log4net>");
                XmlConfigurator.Configure(doc.DocumentElement);

                _loaded = true;
            }
        }

        public void DoB()
        {
            LogPrep.Ensure();
            Log.Debug("DoB");

            var common = new CommonClass();
            common.DoCommon("B");
        }
    }
}

可执行容器:(代表遗留组件)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using ALib;
using BLib;
using log4net;
using log4net.Config;

namespace TestLog4NetRepositories
{
    class Program
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {

            // Set up a simple configuration that logs on the console.

            var doc = new XmlDocument();
            doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
         xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
         debug='true'>
  <appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
    <mapping>
        <level value='DEBUG' />
        <foreColor value='White' />
        <backColor value='Blue' />
    </mapping>
    <layout type='log4net.Layout.PatternLayout'>
      <conversionPattern value='Main: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
    </layout>
  </appender>
  <root>
    <level value='DEBUG' />
    <appender-ref ref='ConsoleAppender' />
  </root>
</log4net>");
            XmlConfigurator.Configure(doc.DocumentElement);

            Log.Info("Entering application.");

            var a = new AClass();
            a.DoA();

            var b = new BClass();
            b.DoB();

            Log.Info("Exiting application.");
        }
    }
}

如果您运行此代码,请注意Common的输出以绿色打印,并且永远不会以红色打印出来。

log4net: Creating repository [BLib] using type [log4net.Repository.Hierarchy.Hierarchy]
log4net:ERROR Failed to alias repository [CommonLib] System.InvalidOperationException: Repository [CommonLib] is already aliased to repository [ALib]. Aliases cannot be redefined.
    at log4net.Core.DefaultRepositorySelector.AliasRepository(String repositoryAlias, ILoggerRepository repositoryTarget)
    at log4net.Core.DefaultRepositorySelector.LoadAliases(Assembly assembly, ILoggerRepository repository)

虽然上面的可执行容器在B之前显示A,但在实际情况中,B可以在A之前。

正如我之前提到的,我有更复杂的层次结构,但上面展示了我面临的最小问题。

0 个答案:

没有答案