使用具有多个线程的Nlog发出在数据库中写入日志
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用具有多个线程的Nlog发出在数据库中写入日志相关的知识,希望对你有一定的参考价值。
我注意到Nlog在通过多个线程在数据库中写日志时遇到了一个奇怪的问题。
问题是一个数据库的日志有时会添加到另一个数据库中,即它们有时会混合在一起。更新Nlog的DbTarget的方法是不是线程安全的,或者我在这里做错了什么?请分享您的想法/经验以应对此问题。
我为三个不同的客户使用相同的单个应用程序,每个客户在同一服务器中有三个不同的数我有C#windows应用程序,其中有3个线程为3个不同的数据库创建。每个线程以如下所示的方式处理它们自己的数据库:
public void StartService()
{
string conn1 = connectionstring for database1;
string conn2 = connectionstring for database2;
Thread ThreadDB1 = new Thread(new ThreadStart(() => Process(conn1)));
Thread ThreadDB2 = new Thread(new ThreadStart(() => Process(conn2)));
ThreadDB1.Start();
ThreadDB2.Start();
}
public void Process(string domainCon)
{
this.isActive = true;
while (this.isActive)
{
try
{
StartOperation(domainCon);
}
catch (Exception ex)
{
//since the Nlog has not been initialised for an individual threads that switch per database,
//If any error occurs here, log that in event log instead
EventLog.WriteEntry("Application", ex.ToString(), EventLogEntryType.Error);
}
}
}
public static void StartOperation(string domainCon)
{
NLogLoggerService loggerService;
NLogLogger Logger;
/* Set the "NEW" instance of logger here so that each instance
* will be per thread (i.e per database) */
Logger = new NLogLogger("MyAppName_Processor");
loggerService = new NLogLoggerService(Logger);
//create the DbTarget that is passed by current thread
Logger.UpdateNLogDatabase(domainCon);
// the process to select the records from Db happens here
ProcessDbRecords(domainCon);
}
ProcessDbRecords(domainCon)
{
//Records are selected, analyzed processed and saved again in database for each thread
//the following log is written in database but log of one database is written in another database sometimes
loggerService.LoggerInfo("The Database has been called for connString: " + domainCon);
}
//in LogService class, i have a method that updates the database target with connectionstring provided in runtime:
public static void UpdateNLogDatabase(string connString)
{
var config = LogManager.Configuration;
var dbTarget = (Targets.DatabaseTarget)config.FindTargetByName("Database");
dbTarget.ConnectionString = connString;
LogManager.ReconfigExistingLoggers();
}
答案
这个想法(使用大多数日志框架)不是不断修改日志记录配置,而是注入想要的上下文信息:
NLog有几种方法可以提供上下文信息:
https://github.com/NLog/NLog/wiki/LogEvent-Context-Information
你可以用MappedDiagnosticsLogicalContext
这样做:
public void Process(string domainCon)
{
this.isActive = true;
NLog.MappedDiagnosticsLogicalContext.Set("ThreadConnectionString", domainCon);
while (this.isActive)
{
try
{
StartOperation(domainCon);
}
catch (Exception ex)
{
//since the Nlog has not been initialised for an individual threads that switch per database,
//If any error occurs here, log that in event log instead
EventLog.WriteEntry("Application", ex.ToString(), EventLogEntryType.Error);
}
}
}
然后在NLog.config中有这个:
<target type="database" connectionString="${mdlc:item=ThreadConnectionString}">
</target>
另见:https://github.com/NLog/NLog/wiki/MDLC-Layout-Renderer
以上是关于使用具有多个线程的Nlog发出在数据库中写入日志的主要内容,如果未能解决你的问题,请参考以下文章