.NET Maui中NLog无法获取全部日志文件的问题排查
NLog日志写入与上传问题排查与解决
问题代码
我们用于获取并上传日志的代码如下:
private async Task GetLogsAndWrite() { _logger.Flush(); var logFiles = Directory.GetFiles(AppConstants.NLogDefaultPath); var logs = new List<string>(); foreach (var log in logFiles) { logs.Add(await File.ReadAllTextAsync(log)); } if (logs is not null && logs.Any()) { foreach (var log in logs) { var logFileName = ("MyLog" + DateTime.Now.ToString("yyyy-MM-ddTHH_mm_ss")).Replace(" ", "") + ".txt"; WriteToFile(log, logFileName); } } }
问题现象
- 上传日志时无法获取全部数据,上传前最后一条日志(如“正在上传日志”提示)未写入上传文件
- 间隔5-10分钟重复上传后,会出现包含之前缺失数据的新日志文件,此时可获取完整信息
- 跨天场景问题更明显:昨日运行生成日志后关闭应用,今日启动操作生成的日志在上传时完全缺失
- 已尝试添加
LogManager.Shutdown();,但无效果,急需强制NLog将所有日志写入磁盘的方法
解决方案
1. 等待Flush操作完成,确保日志落地
_logger.Flush()默认是异步执行的,若直接读取文件会导致部分日志尚未写入磁盘。改为等待异步Flush完成:
// 等待所有日志写入磁盘后再继续 await _logger.FlushAsync();
若使用旧版NLog(无FlushAsync方法),可使用带超时的同步Flush:
// 等待最多5秒,确保日志完成写入 _logger.Flush(TimeSpan.FromSeconds(5));
2. 调整NLog配置,强制即时写入
在NLog配置文件(nlog.config)中,针对文件目标开启autoFlush并关闭keepFileOpen,避免缓存和文件锁定:
<target xsi:type="File" name="fileTarget" fileName="${basedir}/logs/${shortdate}.log" autoFlush="true" <!-- 每条日志写入后立即刷新到磁盘 --> keepFileOpen="false" <!-- 写入完成后释放文件句柄 --> />
3. 确保读取所有日志文件
跨天后NLog会生成新的日期命名日志文件,需确认Directory.GetFiles是否包含所有日志文件。可明确指定文件后缀过滤:
// 读取目录下所有.log格式的日志文件 var logFiles = Directory.GetFiles(AppConstants.NLogDefaultPath, "*.log");
4. 避免读取被锁定的日志文件
若NLog仍持有日志文件句柄,直接读取可能获取不完整内容。可先复制文件到临时目录再读取:
foreach (var logPath in logFiles) { var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(logPath)); // 复制原文件到临时路径,覆盖已存在的临时文件 File.Copy(logPath, tempFilePath, overwrite: true); logs.Add(await File.ReadAllTextAsync(tempFilePath)); // 删除临时文件 File.Delete(tempFilePath); }
5. 直接通过NLog API收集日志(绕过文件读取)
如果文件读取始终存在问题,可自定义NLog目标将日志存储在内存中,上传时直接读取内存数据:
// 自定义内存日志目标 public class InMemoryLogTarget : Target { public static List<string> CollectedLogs { get; } = new List<string>(); protected override void Write(LogEventInfo logEvent) { // 按NLog布局渲染日志内容 var logContent = Layout.Render(logEvent); CollectedLogs.Add(logContent); } } // 在应用启动时注册该目标 var nlogConfig = new LoggingConfiguration(); var memoryTarget = new InMemoryLogTarget(); nlogConfig.AddTarget("memoryLog", memoryTarget); // 配置所有日志级别都写入内存目标 nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, memoryTarget)); LogManager.Configuration = nlogConfig; // 上传时直接使用内存中的日志 var allLogs = InMemoryLogTarget.CollectedLogs;
内容的提问来源于stack exchange,提问作者George M Ceaser Jr
相关产品推荐
相关产品推荐

