我想关闭我的应用程序并写入任何挂起的日志消息。所以我在关机过程中打电话给LogManager.Flush()
。但是,我没有看到所有的消息写出来。相反,如果我等待几秒钟(使用Thread.Sleep()
),我会看到消息。
在检查NLog's code on GitHUB之后,我发现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;
}
答案 0 :(得分:4)
ligos的评论是正确的。
AsyncTargetWrapper.CloseTarget()
方法因NLog issue 134而被修改,其中嵌套的BufferingTargetWrapper
在域名卸载时没有刷新。
LogManager.Shutdown()
确实迫使AsyncTargetWrapper
有效地同步刷新,但必须在LogManager.Flush()
之后使用,因为BufferingTargetWrapper
之类的目标实际上并非如此关闭时冲洗。设置LogManager.Configuration = null
可能会更好,因为这会执行刷新,然后在一次命中时关闭目标,并在下次需要使用时重新加载配置(如果使用配置文件)。
我已经对两者进行了测试,并且我已经使用了后者,因为我希望在我把事情做好之后重新启动并运行,但考虑到Silverlight中的问题我会建议:
LogManager.Flush();
LogManager.Shutdown();
修改强>
LogManager
在域卸载或进程退出时将配置设置为null,因此除非运行旧的NLog版本,否则我们不应该看到此问题。 NLog问题已在2012年10月修复。已经过测试,没有明确关闭或将配置设置为null,并且可以确认调用LogManager.Flush()
已足够。
答案 1 :(得分:0)
仍然不完美,但是这个怎么样:
var reset = new ManualResetEventSlim(false);
LogManager.Flush(ex => reset.Set(), TimeSpan.FromSeconds(15));
reset.Wait(TimeSpan.FromSeconds(15));
答案 2 :(得分:0)
从Buffering log messages in NLog and manually flushes them to target
明目张胆地被盗LogManager.Configuration.AllTargets
.OfType<BufferingTargetWrapper>()
.ToList()
.ForEach(b => b.Flush(e =>
{
//do nothing here
}));
答案 3 :(得分:-1)
我通过编辑当前的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.
}