为什么记录到 log4net.ILog 附加到多个日志?

Why is logging to a log4net.ILog appending to multiple logs?

我正在为第三方应用程序开发一个插件,对于这个插件的每个 'run' 我想要一个独占的日志文件。

我构建了以下 class。

public class LogFileRepository
{
    private readonly Common.Configuration.Settings _configSettings;
    private const string InstanceName = "AutomationPlugin.Logging";
    private readonly ILoggerRepository _repository;


    public LogFileRepository (Common.Configuration.Settings configSettings)
    {
        _configSettings = configSettings;

        var repositoryName = $"{InstanceName}.Repository";
        _repository = LoggerManager.CreateRepository(repositoryName);
    }


    public ILog GetLog(string name)
    {
        var logger = LogManager.Exists(_repository.Name, name);
        if (logger != null)
        {
            return logger;
        }

        var filter = new LevelMatchFilter {LevelToMatch = Level.All};
        filter.ActivateOptions();
        var appender = new RollingFileAppender
                       {
                           AppendToFile = false,
                           DatePattern = "yyyy-MM-dd",
                           File = String.Format(_configSettings.Paths.LogFileTemplate, name),
                           ImmediateFlush = true,
                           Layout = new PatternLayout("%n%date{ABSOLUTE} | %-7p | %m"),
                           LockingModel = new FileAppender.MinimalLock(),
                           MaxSizeRollBackups = 1,
                           Name = $"{InstanceName}.{name}.Appender",
                           PreserveLogFileNameExtension = false,
                           RollingStyle = RollingFileAppender.RollingMode.Once
                       };
        appender.AddFilter(filter);
        appender.ActivateOptions();

        BasicConfigurator.Configure(_repository, appender);

        return LogManager.GetLogger(_repository.Name, name);
    }
}

打算这个函数做的是GetLog方法到return一个日志文件(具有指定的名称)如果LogManager已经有一个;如果没有现有的日志文件,那么它应该实例化并 return 它。

确实发生了。在插件的第一个 运行 中,创建并写入了一个日志文件;在插件的第二个 运行 上,一个新的日志文件被创建并写入,但是所有消息 也被写入第一个日志文件 。在第三次 运行 中,所有消息都 写入两个现有的日志文件 以及新的第三个日志文件。

为什么? RollingFileAppender 中是否有我看似 misunderstood/misconfigured 的内容?我想要每个 name 参数的独占日志文件。

假设您使用 LogManager.CreateRepository() 创建了 _repository,这实际上创建了一个 Hierarchy,当您通过 BasicConfigurator.Configure(_repository, appender); 使用新的附加程序配置它时,这会添加附加程序到层次结构的 Root 附加程序集合。

然后从存储库创建的所有记录器都是 "Root" 的子记录器,并配置为 "additive" 因为它们附加到直接针对它们定义的所有附加程序, 他们的任何父记录器,一直到根。在您的情况下,记录器本身没有自己的附加程序,因此只是从 Root 中获取附加程序,在您的情况下,它包含 all 附加程序。结果,所有消息都记录到每个文件中。

您想要做的是将 appender 附加到它的特定记录器,并禁用可加性,这样它就不会记录到层次结构中更高的 appender。似乎没有 "nice" 方法可以做到这一点,但以下方法在我的测试中有效:

...
appender.AddFilter(filter);
appender.ActivateOptions();

// Add the appender directly to the logger and prevent it picking up parent appenders
if (LoggerManager.GetLogger(_repository.Name, name) is Logger loggerImpl)
{
    loggerImpl.Additivity = false;
    loggerImpl.AddAppender(appender);
}

BasicConfigurator.Configure(_repository, appender);
return LogManager.GetLogger(_repository.Name, name);