【问题标题】:Why is logging to a log4net.ILog appending to multiple logs?为什么记录到 log4net.ILog 会附加到多个日志?
【发布时间】:2018-09-05 11:54:39
【问题描述】:

我正在为第三方应用程序开发一个插件,对于这个插件的每次“运行”,我都需要一个独占的日志文件。

我已经构建了以下类。

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方法返回一个日志文件(具有指定的名称)如果LogManager已经有一个;如果没有现有的日志文件,那么它应该实例化并返回它。

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

为什么? RollingFileAppender 中是否有我似乎误解/错误配置的内容?我想要每个name 参数的专属日志文件。

【问题讨论】:

  • 每次调用都是同一个_repository实例吗?
  • 这能完成你的工作吗:stackoverflow.com/a/18750639/982149 ?
  • @Fildor - 是的,_repository 是类上的私有成员变量,使用此类的代码是一个单例,它在其构造函数中实例化 _repository 的宿主类。所以有一个宿主类的实例,因此有相同的_repository 实例。此外,日志的名称肯定不同 - 否则我永远不会看到创建第二个文件。

标签: c# log4net


【解决方案1】:

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

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

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

...
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);

【讨论】:

    猜你喜欢
    • 2016-08-02
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 2015-09-09
    • 2011-06-12
    • 1970-01-01
    相关资源
    最近更新 更多