I may have stumbled across an issue with NLog, but thought I would check here first for an answer:
To recreate the issue I cloned the NLog source so I could add a delay to cause the problem. Once open in visual studio, I added a console application that references the NLog source projects and makes some very simple log calls. The NLog.config is as follows:
<nlog>
<targets>
<target name="buffer" type="BufferingWrapper">
<target name="logfile" type="File" fileName="log.txt"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>
</nlog>
All works as expected up to this point. The next step is to insert a delay into the flush logic of the FileTarget
. (The reason I found this to be the problem is that I was originally working with the MailTarget
that would hang for a duration whilst connecting to the mail server - I have substituted it for the FileTarget
here instead to make recreating the problem easier).
Open the FileTarget.cs and locate the Write(AsyncLogEventInfo[] logEvents)
method. Insert in the first line Thread.Sleep(5000)
so that the method appears as below:
protected override void Write(AsyncLogEventInfo[] logEvents)
{
Thread.Sleep(5000);
// ... omitted
}
Now, compile and re-run. The log is not written.
As far as I can tell, the logic to flush all targets when the process exits uses an asynchronous method call that has a default timeout of 15 seconds which can be found in the LogFactory.cs Flush()
method - this is obviously not being exceeded.
However, NLog makes use of ThreadPool.QueueUserWorkItem()
(found in AsyncHelpers.cs) to orchestrate the flushing of each target in parallel. Could this simply boil down to a question of how does this form of method invocation react to a call to Thread.Sleep()
, or any other form of blocking (such as connecting to a remote server, as in my original problem)?
Any ideas?