You could try using Trace.CorrelationManager.ActivityId. You can set a value and then use a custom NLog LayoutRenderer to render that value to the output log. You can find an example of a LayoutRenderer that does this here on SO. Look about in the middle of the top answer.
Here is the code for the LayoutRender from that post (note that it was written against NLog 1.0, not NLog 2.0. It should not be hard to update).
[LayoutRenderer("ActivityId")]
class ActivityIdLayoutRenderer : LayoutRenderer
{
int estimatedSize = Guid.Empty.ToString().Length;
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(Trace.CorrelationManager.ActivityId);
}
protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
{
return estimatedSize;
}
}
Your NLog.config would look something like this:
Tell NLog where your NLog extensions are located:
<extensions>
<add assembly="MyNLogExtensions"/>
</extensions>
layout="${threadid} | ${ActivityId} | ${time} | ${level:uppercase=true} | ${logger} | ${message} | ${exception}"
Using your original sample code, you could log something like this:
Private Sub DoParallel
Private Logger As NLog.Logger = NLog.LogManager.GetCurrentClassLogger
Dim ListOfFolder as New List(of String)
ListOfFolder.add("C:\Test.txt")
Trace.CorrelationManager.ActivityId = Guid.Empty;
Parallel.ForEach(listOfFolders, Sub(elem As String)
Trace.CorrelationManager.ActivityId = Guid.NewGuid();
logger.warn("Doing stuff, need to know on which elem it is done")
Trace.CorrelationManager.ActivityId = Guid.Empty;
End Sub)
End Sub
This should uniquely identify each logging statement and, if you had more lines of code in your action, all of the logging statements from a given execution of the action would be tagged with the same guid.
If this approach works for you, you could easily wrap the ActivityId setting/unsetting in an IDisposable class and use the using statement to automate the process.
Please forgive the C#:
public class ActivityIdContext : IDisposable
{
Guid oldActivityId;
public ActivityIdContext(Guid id)
{
oldActivityId = Trace.CorrelationManager.ActivityId;
Trace.CorrelationManager.ActivityId = Guid.NewGuid();
}
public ActivityIdContext() : this(Guid.NewGuid()) { }
public Dispose()
{
Trace.CorrelationManager.ActivityId = oldActivityId;
}
}
Then, you could enclose the body of the Parallel.ForEach action to do something like this (again, in C#)
Parallel.ForEach(listOfFolders, () =>
{
using(new ActivityIdContext())
{
logger.Warn("Hello! I hope the ActivityId helps!");
}
});