问题:原本是通过配置文件设置Appender的<file>节点的值value="Logs\%property{xxx}\"对日志按照xxx变量分类,然后发现运行时在第一次生成后,后续无论怎么更改xxx,后面的日志都生成在第一次生成的日志内。
原因:在经历大量网上冲浪和面向AI编程后,发现原因是Appender初始化时已绑定最终路径,即log4net的Appender在首次初始化(ActivateOptions执行时)会对<file>节点的占位符(包括%property{xxx})进行一次性解析和替换,生成固定的物理日志路径并缓存。后续即使修改了xxx属性的值,由于 Appender 不会主动重新解析<file>节点,也不会刷新已缓存的日志路径,因此新的属性值无法生效,日志仍会输出到最初解析的路径中。
解决:个人解决方法是选择通过代码动态生成Appender
//logger缓存字典
private static Dictionary<string, ILog> _LoggerList = new Dictionary<string, ILog>();
//根据变量名称获取logger
private static ILog GetLoggerByName(string varName)
{
if (!_LoggerList.ContainsKey(varName))
{
//目标logger不存在则生成
_LoggerList[varName] = CreateDynamicLog(varName);
}
return _LoggerList[varName];
}
//动态创建logger
private static ILog CreateDynamicLog(string varName)
{
ILog logger = LogManager.GetLogger(varName);
var hierarchyLogger = (logger.Logger as Logger);
var fileAppender = new RollingFileAppender
{
//动态生成Appender名称
Name = $"{varName}Appender",
//动态生成file路径
File = $"Logs/{varName}/",
DatePattern = "yyyyMMdd'.log'",
AppendToFile = true,
//混合滚动(日期+大小)
RollingStyle = RollingFileAppender.RollingMode.Composite,
//使用动态文件名
StaticLogFileName = false,
MaxSizeRollBackups = 30,
MaximumFileSize = "10MB",
Encoding = System.Text.Encoding.UTF8,
LockingModel = new FileAppender.MinimalLock(),
Layout = new PatternLayout("%date %n%message %n%exception %n")
};
//激活Appender配置
fileAppender.ActivateOptions();
//绑定Appender并刷新配置
hierarchyLogger.AddAppender(fileAppender);
LogManager.GetRepository().ConfigurationChanged += (s, e) => { };
hierarchyLogger.Repository.Configured = true;
return logger;
}
运行时发现生成的日志内容均为空,原因是未设置Logger级别。在创建logger方法中补上语句
//显式设置Logger级别为All
hierarchyLogger.Level = log4net.Core.Level.All;
运行后发现能正常生成日志了,但是又遇到新的问题:每次生成新的logger并写入日志时,缓存字典中存在的logger也会一起写入同样的内容。查阅资(dou)料(bao)后发现是没有禁用累加性(Additivity,又称 “日志传递性”),简单来说:如果启用累加性,一条日志会同时输出到当前 Logger 的 Appender 和所有父 Logger 的 Appender。解决方法很简单,在创建logger方法中再补上语句
//禁用累加性
hierarchyLogger.Additivity = false;
再次运行,日志不会重复写入其他文件了,成功达到预期效果

998

被折叠的 条评论
为什么被折叠?



