调用 Flush() 时,NLog 是否应该刷新 AsyncTargetWrapper 中的所有排队消息

本文关键字:AsyncTargetWrapper 刷新 消息 排队 Flush 是否 NLog 调用 | 更新日期: 2023-09-27 18:33:24

我想关闭我的应用程序并写入任何挂起的日志消息。所以我在关机过程中打电话给LogManager.Flush()。但是,我没有看到所有消息都写出来了。相反,如果我等待几秒钟(使用 Thread.Sleep() (,我会看到消息。

在 GitHUB 上检查了 NLog 的代码后,我发现AsyncTargetWrapper.FlushAsync()方法只是调度惰性编写器线程在下一批上写入所有挂起的消息。它不会同步写入日志消息。

这是预期的行为吗?我希望LogManager.Flush()是同步的,即:阻止直到写入所有挂起的消息(或超过超时(。


我在关机时使用的代码:

LogManager.Flush(ex => { }, TimeSpan.FromSeconds(15));

然后是初始化Nlog的代码(这是一个Silverlight应用程序,所以我没有使用任何配置文件(。

    public static void InitialiseNLog(LogLevel forLevel)
    {
        var config = new LoggingConfiguration();
        // Add targets.
        // We need an async target wrapping a custom web service call back to the server.
        var serverTarget = new RemoteServiceTarget();
        var asyncWrapper = new AsyncTargetWrapper(serverTarget, 10000, AsyncTargetWrapperOverflowAction.Discard);
        asyncWrapper.TimeToSleepBetweenBatches = (int)TimeSpan.FromSeconds(2).TotalMilliseconds;
        asyncWrapper.BatchSize = 200;
        // Add rules.
        var rule = new LoggingRule("Company.Application.SilverlightApp.*", forLevel, asyncWrapper);
        config.LoggingRules.Add(rule);
        // Activate the configuration.
        LogManager.Configuration = config;
        LogManager.GlobalThreshold = forLevel;
    }

调用 Flush() 时,NLog 是否应该刷新 AsyncTargetWrapper 中的所有排队消息

ligos 的评论是正确的。由于 NLog 问题 134,AsyncTargetWrapper.CloseTarget()方法已修改,其中嵌套BufferingTargetWrapper在域卸载时未刷新。

LogManager.Shutdown()确实会强制AsyncTargetWrapper有效地同步刷新,但必须在LogManager.Flush()后使用它,因为BufferingTargetWrapper等目标实际上不会在关闭时刷新。最好设置LogManager.Configuration = null因为这会执行刷新,然后一次性关闭目标,下次需要使用配置时将重新加载(如果使用配置文件(。

我已经测试了两者,并且我已经选择了后者,因为我希望在正确处理后恢复登录并运行,但鉴于问题在 Silverlight 中,我建议:

LogManager.Flush();
LogManager.Shutdown();

编辑

LogManager在域卸载或进程退出时将配置设置为 null,因此除非运行旧的 NLog 版本,否则我们不应该看到此问题。NLog 问题已于 2012 年 10 月修复。在没有显式关闭或将配置设置为 null 的情况下进行了测试,并且可以确认调用LogManager.Flush()就足够了。

公然窃取:在 NLog 中缓冲日志消息并手动将其刷新到目标

LogManager.Configuration.AllTargets
.OfType<BufferingTargetWrapper>()
.ToList()
.ForEach(b => b.Flush(e =>
    {
        //do nothing here
    }));

我已经通过编辑当前的 NLog 源代码实现了修复。

在 AsyncTargetWrapper.cs 中,将FlushAsync()方法从:

protected override void FlushAsync(AsyncContinuation asyncContinuation)
{
    this.flushAllContinuation = asyncContinuation;
}

自:

protected override void FlushAsync(AsyncContinuation asyncContinuation)
{
    this.flushAllContinuation = asyncContinuation;
    this.ProcessPendingEvents(null);        // Added to make this flush synchronous.
}
相关文章:
  • 没有找到相关文章