您可以尝试使用Trace.CorrelationManager.ActivityId。您可以设置一个值,然后使用自定义 NLog LayoutRenderer 将该值呈现到输出日志。您可以在 SO 上找到执行此操作的 LayoutRenderer 示例。在最佳答案的中间查看。
这是该帖子中 LayoutRender 的代码(请注意,它是针对 NLog 1.0 而不是 NLog 2.0 编写的。应该不难更新)。
[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;
  }
}
你的 NLog.config 看起来像这样:
告诉 NLog 你的 NLog 扩展在哪里:
<extensions>
    <add assembly="MyNLogExtensions"/>
</extensions>
layout="${threadid} | ${ActivityId} | ${time} | ${level:uppercase=true} | ${logger} | ${message} | ${exception}"
使用您的原始示例代码,您可以记录如下内容:
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
这应该唯一标识每个日志记录语句,并且如果您的操作中有更多代码行,那么来自给定操作执行的所有日志记录语句都将使用相同的 guid 进行标记。
如果这种方法适合您,您可以轻松地将 ActivityId 设置/取消设置包装在 IDisposable 类中,并使用 using 语句来自动化该过程。  
请原谅 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;
  }
}
然后,您可以包含 Parallel.ForEach 动作的主体来执行类似的操作(同样,在 C# 中)
Parallel.ForEach(listOfFolders, () =>
{
  using(new ActivityIdContext())
  {
    logger.Warn("Hello!  I hope the ActivityId helps!");
  }
});