为什么记录到 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);
我正在为第三方应用程序开发一个插件,对于这个插件的每个 '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);