如何为独立类库程序集配置和启用log4net?

Zac*_*ame 32 .net c# log4net

背景

我正在用C#.NET 3.5编写一个类库程序集,用于与其他应用程序集成,包括第三方商用现成(COTS)工具.因此,有时这个类库将由我控制的应用程序(EXE)调用,而有时它将被其他DLL或我无法控制的应用程序调用.

假设

  • 我使用的是C#3.0,.NET 3.5 SP1和Visual Studio 2008 SP1
  • 我使用的是log4net 1.2.10.0或更高版本

约束

任何解决方案必须

  • 如果调用应用程序未配置log4net,则允许类库通过其自己的配置文件启用和配置日志记录.
  • 允许类库通过调用应用程序配置启用和配置日志记录(如果它指定了log4net信息)

要么

  • 允许类库始终使用自己的配置文件启用和配置日志记录.

问题

当我的独立类库由我无法控制的DLL或应用程序(例如第三方COTS工具)调用且未指定log4net配置信息时,我的类库无法执行任何日志记录.


如何为独立类库程序集配置和启用log4net,以便无论调用应用程序是否提供log4net配置,它都将记录?

Jac*_*cob 12

您可以在XmlConfigurator类周围编写代码:

public static class MyLogManager
{
    // for illustration, you should configure this somewhere else...
    private static string configFile = @"path\to\log4net.config";

    public static ILog GetLogger(Type type)
    {
        if(log4net.LogManager.GetCurrentLoggers().Length == 0)
        {
            // load logger config with XmlConfigurator
            log4net.Config.XmlConfigurator.Configure(configFile);
        }
        return LogManager.GetLogger(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的课程中,而不是:

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)

使用:

private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)

当然,最好将此类作为服务并使用您选择的IoC容器动态配置它,但您明白了吗?

编辑:修复注释中指出的Count()问题.


Zac*_*ame 12

解决方案1

第一组约束的解决方案是基本上将log4net.LogManager包装到您自己的自定义LogManager类中,如Jacob,JeroenMcWafflestix所建议的(参见下面的代码).

不幸的是,log4net.LogManager类是静态的,C#不支持静态继承,因此您不能简单地继承它并覆盖GetLogger方法.但是,log4net.LogManager类中没有太多方法,所以这肯定是可能的.

这个解决方案的另一个缺点是,如果你有一个现有的代码库(我在我的情况下),你将不得不用你的包装类替换所有现有的log4net.LogManager调用.然而,今天的重构工具并没有什么大不了的.

对于我的项目,这些缺点超过了使用调用应用程序提供的日志记录配置的好处,因此,我选择了解决方案2.

首先,您需要一个LogManager包装类:

using System;
using System.IO;
using log4net;
using log4net.Config;

namespace MyApplication.Logging
{
    //// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.
    public static class LogManagerWrapper
    {
        private static readonly string LOG_CONFIG_FILE= @"path\to\log4net.config";

        public static ILog GetLogger(Type type)
        {
            // If no loggers have been created, load our own.
            if(LogManager.GetCurrentLoggers().Length == 0)
            {
                LoadConfig();
            }
            return LogManager.GetLogger(type);
        }

        private void LoadConfig()
        {
           //// TODO: Do exception handling for File access issues and supply sane defaults if it's unavailable.   
           XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));
        }              
}
Run Code Online (Sandbox Code Playgroud)

然后在你的课程中,而不是:

private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)

使用:

private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)

解决方案2

出于我的目的,我决定采用符合第二组约束的解决方案.请参阅下面的代码了解我的解决方案

Apache log4net文档:

"程序集可以选择使用命名的日志存储库而不是默认存储库.这会将程序集的日志记录与应用程序的其余部分完全分开.这对于希望将log4net用于其组件的组件开发人员非常有用.不希望要求所有使用其组件的应用程序都知道log4net.这也意味着他们的调试配置与应用程序配置分离.程序集应指定RepositoryAttribute来设置其日志存储库."

我将以下行放在我的类库的AssemblyInfo.cs文件中:

// Log4Net configuration file location
[assembly: log4net.Config.Repository("CompanyName.IntegrationLibName")]
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "CompanyName.IntegrationLibName.config", Watch = true)]
Run Code Online (Sandbox Code Playgroud)

    

参考


Jer*_*ink 7

在您的代码中,您可以检查是否有任何记录器通过

log4net.LogManager.GetCurrentLoggers().Count()
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用XmlConfigurator从文件加载默认配置:

log4net.Config.XmlConfigurator.Configure(configFile)
Run Code Online (Sandbox Code Playgroud)

您可以在静态或常规构造函数中进行初始化.

class Sample
{
    private static readonly log4net.ILog LOG;

    static Sample()
    {
        if (log4net.LogManager.GetCurrentLoggers().Count() == 0)
        {
            loadConfig();
        }
        LOG = log4net.LogManager.GetLogger(typeof(Sample));

    }

    private static void loadConfig()
    {
        /* Load your config file here */
    }

    public void YourMethod()
    {
       LOG.Info("Your messages");
    }
}
Run Code Online (Sandbox Code Playgroud)