C# 如何使NLog线程在运行时安全地写入单独的文件目标?

C# 如何使NLog线程在运行时安全地写入单独的文件目标?,c#,multithreading,nlog,C#,Multithreading,Nlog,我有一个运行多个线程(~50)的应用程序,每个线程都会从数据库获取一个带锁的付款,然后进行处理。 但是,50个线程使日志无法读取、混淆,并且文件量巨大。 现在,我想让NLog为每个支付ID写入一个单独的文件,以便将支付处理的所有历史记录存储在一个文件中 NLog配置文件: <?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns

我有一个运行多个线程(~50)的应用程序,每个线程都会从数据库获取一个带锁的付款,然后进行处理。
但是,50个线程使日志无法读取、混淆,并且文件量巨大。
现在,我想让NLog为每个支付ID写入一个单独的文件,以便将支付处理的所有历史记录存储在一个文件中

NLog配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="file" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\Immediate\${shortdate}.server.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="file"/>
  </rules>
</nlog>
我所期望的是:

private static readonly ILogger GeneralLogger = LogManager.GetCurrentClassLogger(); // "2017-07-20.General.log"

while (!_cancellationToken.IsCancellationRequested)
{
    using (var session = _connectionFactory.GetSession())
    {
        AcquirePaymentWithUpdlockReadpast(session, 
            GeneralLogger, // "2017-07-20.General.log"
            payment => {
                if (payment == null)
                    return;

                var paymentLogger = LogManager.GetCurrentClassLogger();
                paymentLogger.FileName = $"Payment-{payment.Id}.log"; // <-- I want this. 
                paymentLogger.Debug($"Payment has been acquired for processment");

                ProcessPayment(session, paymentLogger, payment); // "2017-07-20.Payment-123.log"
            });
    }

    Thread.Sleep(50);
}
private static readonly ILogger GeneralLogger=LogManager.GetCurrentClassLogger();//“2017-07-20.一般记录”
而(!\u cancellationToken.IsCancellationRequested)
{
使用(var session=\u connectionFactory.GetSession())
{
AcquirePaymentWithUpdlockReadpast(会话,
GeneralLoger,/“2017-07-20.通用日志”
付款=>{
如果(付款==null)
返回;
var paymentLogger=LogManager.GetCurrentClassLogger();

paymentLogger.FileName=$“Payment-{Payment.Id}.log”;//可能是这样的:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="file" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\Immediate\${shortdate}.server.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
    <target name="paymentFile" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="p" xsi:type="File" fileName="C:\LogFiles\Immediate\Payment-${event-properties:PaymentID:whenEmpty=0}.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="paymentFile">
         <condition="'${event-properties:PaymentID:whenEmpty=0}'!='0'" action="LogFinal" />
    </logger>
    <logger name="*" minlevel="Debug" writeTo="file"/>
  </rules>
</nlog>
替代解决方案可以是这样的:

var paymentLogger = LogManager.GetLogger($"Payment-{payment.Id}");
paymentLogger.Debug($"Payment has been acquired for processment")
然后将记录器过滤器更改为:

<logger name="Payment-*" minlevel="Debug" writeTo="paymentFile" />

感谢Rolf Kristensen的回答,我使用了第二种方法,但找到了一个类似但较短的解决方案,它使用
name
属性:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="all" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\${shortdate}.All.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
    <target name="perLoggerName" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\${shortdate}.${logger}.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="all"/>
    <logger name="Document-*" minlevel="Debug" writeTo="perLoggerName"/>
    <logger name="Job-*" minlevel="Debug" writeTo="perLoggerName"/>
  </rules>
</nlog>


非常感谢您的回答。第二种方法确实帮助了我,我从来都不知道我可以这样使用logger名称。但是,我发现了一个使用
name
属性的简短解决方案,您可能会感兴趣:)考虑将openFileCacheSize=“25”和openFileCacheTimeout=“600”添加到包装在下面的文件目标中“PrLogGrame”(因为您将为每个记录器名称获得一个挂起的文件状态)。请考虑将文件目标重命名为“PrLogGrame”到“P”(而不是“F”)。
<logger name="Payment-*" minlevel="Debug" writeTo="paymentFile" />
fileName="C:\LogFiles\Immediate\{logger}.log" 
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="all" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\${shortdate}.All.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
    <target name="perLoggerName" xsi:type="AsyncWrapper" queueLimit="10000" overflowAction="Discard">
      <target name="f" xsi:type="File" fileName="C:\LogFiles\${shortdate}.${logger}.log" layout="${longdate}|${level}|${processid}|${threadid}|${level:upperCase=true}|${callsite:className=false}|${message}" encoding="utf-8"/>
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="all"/>
    <logger name="Document-*" minlevel="Debug" writeTo="perLoggerName"/>
    <logger name="Job-*" minlevel="Debug" writeTo="perLoggerName"/>
  </rules>
</nlog>