You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:39:53