我有一个运行多个线程(~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 Logger = LogManager.GetCurrentClassLogger(); // "2017-07-20.log"
while (!_cancellationToken.IsCancellationRequested)
{
using (var session = _connectionFactory.GetSession())
{
AcquirePaymentWithUpdlockReadpast(session,
Logger, // "2017-07-20.log"
payment => {
if (payment == null)
return;
Logger.Debug($"Payment {payment.Id} has been acquired for processment");
ProcessPayment(session, Logger, payment); // "2017-07-20.log"
});
}
Thread.Sleep(50);
}
我的期望是:
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);
}
我找到了一些使用LogManager.Configuration
的解决方案,但它似乎不是线程安全的。
答案 0 :(得分:4)
也许是这样的:
<?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>
然后你可以像这样进行日志记录(可以使用NLog-Fluent进行改进):
LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, $"Payment has been acquired for processment");
theEvent.Properties["PaymentID"] = payment.Id;
Logger.Debug(theEvent);
替代解决方案可能是这样的:
var paymentLogger = LogManager.GetLogger($"Payment-{payment.Id}");
paymentLogger.Debug($"Payment has been acquired for processment")
然后将logger-filter更改为:
<logger name="Payment-*" minlevel="Debug" writeTo="paymentFile" />
然后将paymentFile文件名更改为:
fileName="C:\LogFiles\Immediate\{logger}.log"
答案 1 :(得分:1)
感谢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>