Log4net配置:实现重启应用仍追加日志至同一文件
解决log4net重复生成日志文件的问题
我来帮你搞定这个日志文件的问题——你当前的配置里,每次启动应用时log4net都会重新解析%date{yyyyMMdd_HHmmss}这个表达式,所以每次都会生成一个新的文件名,哪怕appendToFile设为true也没用,因为目标文件不一样嘛。
想要实现仅在首次启动(或旧文件被删/重命名时)创建带生成时间的日志文件,之后一直追加到该文件的需求,这里有两种可行方案:
方案一:启动时手动检查并确定日志文件名(完全贴合需求)
这个方法逻辑直观,能精准满足你的要求:每次启动先检查目标目录有没有符合格式的日志文件,有就追加,没有就新建带当前时间的文件。
步骤1:修改App.config配置
把原来的文件名表达式替换为log4net的全局属性占位符,这样我们可以在代码里动态设置文件名:
<appender name="FileAppender" type="log4net.Appender.FileAppender"> <!-- 用全局属性作为文件名占位符 --> <file type="log4net.Util.PatternString" value="%property:LogFileName" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date{dd-MMM-yyyy HH:mm:ss,fff} %level - %message%newline" /> </layout> </appender>
步骤2:在应用启动时设置日志文件名
在应用的入口(比如Program.cs的Main方法)里添加逻辑,检查现有文件并设置全局属性:
using System.IO; using System.Linq; using log4net; using log4net.Config; namespace YourAppNamespace { class Program { static void Main(string[] args) { // 定义日志存储目录和文件名规则 string logDirectory = @"D:\"; string logFilePrefix = "Log_"; string logFileExtension = ".txt"; // 确保目录存在 if (!Directory.Exists(logDirectory)) { Directory.CreateDirectory(logDirectory); } // 查找目录下所有符合格式的日志文件 var existingLogFiles = Directory.GetFiles(logDirectory, $"{logFilePrefix}*{logFileExtension}"); string targetLogFile; if (existingLogFiles.Length > 0) { // 取最新创建的日志文件(你也可以根据需求选择其他规则,比如最早的) targetLogFile = existingLogFiles .OrderByDescending(filePath => new FileInfo(filePath).CreationTime) .First(); } else { // 生成新的带当前时间的文件名 string currentTimeStamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); targetLogFile = Path.Combine(logDirectory, $"{logFilePrefix}{currentTimeStamp}{logFileExtension}"); } // 设置log4net全局属性,供配置文件使用 log4net.GlobalContext.Properties["LogFileName"] = targetLogFile; // 初始化log4net XmlConfigurator.Configure(); // 测试日志 var logger = LogManager.GetLogger(typeof(Program)); logger.Info("应用启动成功"); } } }
这样每次启动应用时:
- 如果目标目录有日志文件,就追加到最新的那个
- 如果文件被删除或重命名,就自动创建带当前时间的新文件
- 你的原有日志调用代码(比如
ABC类里的logMe.Info)完全不用修改,直接生效
方案二:自定义PatternConverter缓存首次启动时间(适合固定文件名场景)
如果你希望文件名固定为应用首次启动的时间(即使旧文件被删,新创建的文件名还是首次启动的时间),可以用这种方式:
步骤1:创建自定义PatternConverter
这个转换器会在首次加载时记录当前时间,之后一直返回这个缓存值:
using log4net.Util; using System; namespace YourAppNamespace { public class LogCreationTimeConverter : PatternConverter { private static readonly string _creationTimeStamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); protected override void Convert(System.IO.TextWriter writer, object state) { writer.Write(_creationTimeStamp); } } }
步骤2:修改App.config注册转换器并使用
<log4net> <!-- 注册自定义转换器 --> <converter> <name>logCreationTime</name> <!-- 替换成你的程序集名称,比如你的项目编译后的exe/dll名字 --> <type>YourAppNamespace.LogCreationTimeConverter, YourAppAssembly</type> </converter> <appender name="FileAppender" type="log4net.Appender.FileAppender"> <!-- 使用自定义转换器生成文件名 --> <file type="log4net.Util.PatternString" value="D:\Log_%logCreationTime.txt" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date{dd-MMM-yyyy HH:mm:ss,fff} %level - %message%newline" /> </layout> </appender> <root> <level value="ALL" /> <appender-ref ref="FileAppender" /> </root> </log4net>
注意:这个方案的文件名是固定的,即使旧文件被删除,重新创建的文件名还是首次启动的时间,不符合“删除后创建新的带当时时间的文件”的需求,所以更适合需要固定文件名的场景。
你的原有日志调用代码无需任何修改,配置完成后就能正常工作。
内容的提问来源于stack exchange,提问作者John Evans Solachuk
相关产品推荐
相关产品推荐

