并行循环和Nlog

时间:2012-10-16 09:38:46

标签: vb.net parallel-processing nlog

我对parallel.for循环中的文件执行一些操作,为其创建日志。但我需要知道哪个操作创建了特定的日志条目。我尝试在我的nlog-config中使用{ThreadID},但threadID由parallel.for循环重用,因此似乎没有唯一标识符。 任何建议如何为每个文件提供唯一的日志标识符?

基本代码:

Private Sub DoParallel
 Private Logger As NLog.Logger = NLog.LogManager.GetCurrentClassLogger 
 Dim ListOfFolder as New List(of String)
 ListOfFolder.add("C:\Test.txt")

 Parallel.ForEach(listOfFolders, Sub(elem As String)
     logger.warn("Doing stuff, need to know on which elem it is done")
  End Sub)
End Sub

Nlog配置:

 layout="${threadid} | ${time} | ${level:uppercase=true} | ${logger} | ${message} | ${exception}"

1 个答案:

答案 0 :(得分:1)

您可以尝试使用Trace.CorrelationManager.ActivityId。您可以设置一个值,然后使用自定义NLog LayoutRenderer将该值呈现给输出日志。您可以找到执行this here on 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!");
  }
});