log4net使用类名记录器

时间:2016-04-19 01:00:30

标签: .net log4net

我想记录多个文件(仅限2个不同的文件),但保留记录器名称与类名称相同,如通常所做的那样:

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

我想保留类名,以便将其输出到记录器。

问题是,我需要根据被调用的wcf方法在appender之间动态切换(这是一个wcf服务)。我尝试了各种log4net配置设置,包括这个解决方案:

Configure Log4net to write to multiple files

但是许多解决方案都有预定义的记录器名称,我不想要。我也不想在log4net配置中硬编码我所有不同的类名,并引用那些特定的记录器(维护噩梦)。

我正在寻找的是这样的:

public static ILog GetLogger(Type classType, bool shouldLogToFile2)
{
    if (shouldLogToFile2)
    {
        return LogManager.GetLogger(classType, file2Appender); // log to file2.log (this statement doesn't compile)
    }
    else
    {
        return LogManager.GetLogger(classType, file1Appender); // log to file1.log (this statement doesn't compile)
    }
}

并称之为:

ILog log = GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, true);
log.Info("This should log to file2.log");

2 个答案:

答案 0 :(得分:1)

如果您想拥有多个具有相同名称但使用不同appender的记录器,则必须设置多个存储库以包含它们。

正如the (somewhat scanty) documentation on repositories中所述:

  

可以使用LogManager.CreateRepository方法创建命名日志记录存储库。可以使用LogManager.GetRepository方法检索存储库。以这种方式创建的存储库需要以编程方式配置。

但是,这并不意味着实际配置必须在代码中,但您应该这样做:

// or wherever
string configPath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 

var repository = log4net.LogManager.CreateRepository("file1repo");
log4net.XmlConfigurator.ConfigureAndWatch(repository, new FileInfo(configPath));

repository = log4net.LogManager.CreateRepository("file2repo");
log4net.XmlConfigurator.ConfigureAndWatch(repository, new FileInfo(configPath));

然后你会编写代码来修改' file2'写入file2的appender:

var appender = LogManager.GetRepository("file2repo").GetAppenders()
                         .OfType<RollingFileAppender>().Single();

appender.File = "file2.log";
appender.ActivateOptions(); 

您的代码如下所示:

public static ILog GetLogger(Type classType, bool shouldLogToFile2)
{
    return LogManager.GetLogger(shouldLogToFile2 ? "file2repo" : "file1repo", classType);
}

答案 1 :(得分:0)

玩了几个小时之后,这就是我想出来的。

这个想法是为每个记录器名称添加“File2”作为应该附加到file2.log的记录器的前缀。然后根据传入的布尔值返回您正在查找的相应记录器。

为了防止将日志消息写入这两个文件,我决定将所有记录器从根记录器中取出(参见config)并在代码中明确使用每个appender。

配置:

<log4net>       
    <appender name="File1Appender" type="log4net.Appender.RollingFileAppender">
      <file value="c:\file1.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="50MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5p %logger %message%newline" />
      </layout>
    </appender>

    <appender name="File2Appender" type="log4net.Appender.RollingFileAppender">
      <file value="c:\file2.log" />
      <appendToFile value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="50MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5p %logger %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="ALL" />      
    </root>
    <logger name="LoggerF1">
      <appender-ref ref="File1Appender" />
    </logger>
    <logger name="LoggerF2">
      <appender-ref ref="File2Appender" />
    </logger>
</log4net>

代码:

public static ILog GetLogger(Type classType, bool shouldLogToFile2 )
{
    ILog newLogger = log4net.LogManager.GetLogger(shouldLogToFile2 ? "File2." + classType.ToString() : classType.ToString());
    Logger loggerInstance = (Logger) newLogger.Logger;
    // if the newLogger doesn't have an appender (which it won't the first time it's created) then add the appropriate appender
    if (loggerInstance.Appenders.Count == 0)
    {           
        IAppender[] appenders = LogManager.GetRepository().GetAppenders();
        IAppender appender = appenders.SingleOrDefault(a => a.Name == (shouldLogToFile2 ? "File2Appender" : "File1Appender"));
        loggerInstance.AddAppender(appender);           
    }
    return newLogger;
}

这种方式都是在配置中完成的,并且代码中没有重复配置。我想要两个appender使用相同的日志级别,这就是为什么我把它放在根记录器而不是每个单独的记录器中。