【问题标题】:Parellel Loop and Nlog并行循环和 Nlog
【发布时间】:2012-10-16 09:38:45
【问题描述】:

我对为其创建日志的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}"

【问题讨论】:

    标签: vb.net parallel-processing nlog


    【解决方案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!");
      }
    });
    

    【讨论】:

    • 哇,看起来棒极了!我今天的工作日结束了,但明天早上我会试试你的方法。你的工作给我留下了深刻的印象,非常感谢!
    • 工作就像一个魅力。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    相关资源
    最近更新 更多