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

时间:2009-06-22 17:10:41

标签: c# .net 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信息)

OR

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

问题

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


问题

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

6 个答案:

答案 0 :(得分: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);
    }
}

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

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

使用:

private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp));

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

编辑:已在评论中指出修复了Count()问题。

答案 1 :(得分:12)

解决方案1 ​​

第一组约束的解决方案是基本上将log4net.LogManager包装到您自己的自定义LogManager类中,如JacobJeroenMcWafflestix已建议(请参阅代码如下)。

不幸的是,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));
        }              
}

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

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

使用:

private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp));

解决方案2

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

来自Apache log4net document

“程序集可以选择使用命名的日志存储库而不是默认存储库。这会将程序集的日志记录与应用程序的其余部分完全分开。这对于希望使用的组件开发人员非常有用。 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)]

参考

答案 2 :(得分:7)

在您的代码中,您可以通过

检查是否有任何记录器
log4net.LogManager.GetCurrentLoggers().Count()

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

log4net.Config.XmlConfigurator.Configure(configFile)

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

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");
    }
}

答案 3 :(得分:1)

在您的独立类库中,有一个使用log4net加载log4net.Config.XmlConfigurator配置文件的单例。

具体来说,您可以定义所有代码以使用自己的自定义日志记录类;这个类可以只是log4net日志记录调用的简单包装器,只需添加一个;创建一个静态成员,其中包含您要登录的日志信息;通过在该类的静态构造函数中调用XmlConfigurator来初始化它。这就是你所要做的一切。

答案 4 :(得分:1)

你可以在这里找到一个很好的描述: log4net: A quick start guide

如文章所述,要在每个程序集分别配置它之前,为名为AssemblyName.dll.log4net的程序集创建一个XML文件,并将以下XML代码放入其中:

<?xml version="1.0" encoding="utf-8"?>
<log4net debug="false">
   <appender name="XmlSchemaFileAppender" type="log4net.Appender.FileAppender">
      <file value="AppLog.xml" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.XmlLayout" />
   </appender>

   <root>
      <level value="WARN" />
      <appender-ref ref="XmlSchemaFileAppender" />
   </root>
</log4net>

它进一步描述了,要实例化一个新的记录器,只需将它声明为整个类的变量,如下所示:

public class LogSample
{
    private static readonly log4net.ILog Log 
            = log4net.LogManager.GetLogger(typeof(LogSample));
    // Class Methods Go Here...
}

然后,您可以在类中使用私有变量Log,如:

Log.Info("Sample message");

同样,您可以使用Log.Error("Error occurred while running myMethod", ex)记录错误以及异常详细信息。

我发现以下内容:

  • 请勿忘记致电log4net.Config.XmlConfigurator.Configure();以激活您的配置

  • 如果您需要知道所写文件的路径,here一些代码如何从L​​og4Net获取

我希望这会有所帮助。

答案 5 :(得分:0)

这对我来说适用于共享库

protected static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.Assembly.GetExecutingAssembly().GetType());