使用具有多个线程的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发出在数据库中写入日志的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 Nlog 将日志写入 Azure

.NET Core使用Nlog记录日志

.Net -- NLog日志框架配置与使用

Net Core 2.1 日志记录框架NLog+Mysql配置

从 msi 安装程序安装时,NLog 不写入日志

Nlog不会写入Windows服务中的日志文件