c#-4.0 - Nlog 未将所有行写入并行循环中的文件

标签 c#-4.0 logging visual-studio-2013 nlog parallel.foreach

我正在使用 Nlog 根据要求,我正在并行循环中处理几千条记录

对于每个项目,在按特定顺序(管道过滤器模式)进行多次操作后,我想将特定记录(无法加载到数据存储中)写入到输出文件夹中。

此输出文件夹不是 {basedir} 而是特定于每个客户端的文件夹,因此我使用 nlog 和 nlog 变量以及如下相关配置将值写入多线程应用程序的文件中。

在配置文件中

<variable name="outPutFileFullName" value=""/>

<target xsi:type="File" name="OutPutFile" fileName="${mdc:item=outPutFileFullName}"
        layout="${message}"/>

<logger name ="ABC" 
 level="Info" writeTo="OutPutFile"></logger>

在代码中

_loggingService.SetMappedDiagnosticsContext("outPutFileFullName", outPutFolderFile);


 Parallel.ForEach(allItems
               itemLine =>
     {
       itemLine.OutPutFileFullName = outPutFolderFile;
       var pipeLine = new PipeLine<TEST>();
       pipeLine.Register(new Operation1<TEST>(_loggingService))
       .Register(new Operation2<TEST>(_loggingService))
     .Register(new Operation3<TEST>(_loggingService))
      .Execute(itemLine);
   });

在操作3中我有一个简单的方法

 private  void WriteToFileFromObject(Test obj)
 {
   LoggingService.Info(obj.FileLineNumber.ToString());
 }

我预计这个过程会写入 100 条记录,但它始终只写入 17 条记录,但不相同且不按特定顺序。

如果我更改fileName="${mdc:item=outPutFileFullName}" 在配置文件中将其设置为常量值,例如 fileName="${basedir}/logs/Test.log" 然后将所有 100 条记录写入文件。知道为什么吗?

最佳答案

MappedDiagnosticsContext 使用线程本地存储。 Parallel.ForEach 将使用其他线程/任务,这些线程/任务将无法访问您放入 MappedDiagnosticsContext 中的值(因为该值是特定线程的本地值)。如果您只为应用程序设置此值一次,那么也许您可以使用 GlobalDiagnosticsContext。

我怀疑正在写入的 17 个项目来自主线程(即设置 MDC 值的同一线程)上发生的执行。其余的可能发生在不同的线程上。由于 MDC 中没有这些线程的值,因此文件名为 null(或为空)。

另外,我不明白您希望通过配置中的这一行实现什么目的:

<variable name="outPutFileFullName" value=""/>

在 nlog.config 文件中声明变量允许您稍后在配置中使用该变量名称。变量与引用 MDC/GDC 中的项目没有任何关系,至少不是直接关系。有关如何在 nlog.config 中使用变量的一些示例,请参阅此答案:

Most useful NLog configurations

为了完整起见,我将提到 log4net 有一个 LogicalThreadContext(除了对应于 NLog 的 MDC 和 GDC 的上下文)。 LogicalThreadContext 使用 LogicalSetData 将值存储在 CallContext 中。在这种情况下,存储在 LogicalThreadContext 中的所有值都将“流向”任何子线程或任务。因此,如果在线程 A 中存储一个名为“Name”的值,然后线程 A 启动一些子线程(或任务),则值“Name”将在每个子线程(或任务)的 LogicalThreadContext 中可用。

在您的示例中,如果您使用 log4net 并在主线程中设置值,如下所示:

log4net.LogicalThreadContext.Properties["outputFilename"] = outputFolderFile;

那么该值将在并行处理启动的所有线程/任务中可用。

这是 Jeffrey Richter 撰写的一篇文章,描述了 CallContext.LogicalSetData 的工作原理:

http://www.wintellect.com/blogs/jeffreyr/logical-call-context-flowing-data-across-threads-appdomains-and-processes

关于c#-4.0 - Nlog 未将所有行写入并行循环中的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27797279/

相关文章:

c# - 将数据表转换为字节数组

c++ - 通过代码确定控制台是否应保存到文件(以及该文件的名称)

c++ - 简单的 C++ 日志记录类 - ostream 引用初始化

c++ - 雕刻 1.4 CSG - C2375 : 'cbrt' : redefinition; different linkage

.net - 使用C#中的任务并行库,每个处理器运行一个并行任务

.net - ConcurrentDictionary TryGetValue 与 []。 [] 仍然是线程安全的吗?

asp.net - 动态创建excel文件并自动下载

logging - 寻找用于记录的调用或线程 ID

c# - Visual Studio 2013 远程调试、自动部署?

c - 从开发人员命令提示符或 C 语言中的 MVS 编译 DLL 库之间的区别