【问题标题】:Issue writing log in database with Nlog with multiple threads使用具有多个线程的 Nlog 在数据库中写入日志问题
【发布时间】:2019-04-18 12:01:10
【问题描述】:

在通过多个线程将日志写入数据库时​​,我注意到 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();
}

【问题讨论】:

  • 据我了解,您正在更改全局配置,因此它将影响所有记录器(我的意思是,该方法名为ReconfigExistingLoggers,所以它有点放弃了)。因此,更改 dbtarget 的连接字符串的线程将影响其他线程。我认为您需要为每个记录器使用不同的目标
  • 嗨@KevinGosse,谢谢你的回复。您能否提供一些详细信息,我如何为每个记录器实现不同的目标?

标签: c# asp.net multithreading thread-safety nlog


【解决方案1】:

这个想法(对于大多数日志框架)不是不断修改日志配置,而是注入所需的上下文信息:

NLog 有几个选项来提供上下文信息:

https://github.com/NLog/NLog/wiki/Context

您可以使用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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    相关资源
    最近更新 更多