带有MDLC和NDLC的线程间奇怪的NLog行为

时间:2019-07-01 14:29:03

标签: c# multithreading nlog

我正在尝试跨线程设置CorrelationID,以在对服务器的调用与对外部Web服务的相应调用之间建立链接。相关性ID是一个GUID,我将其保存在NLog的Logical Context结构中(逻辑上下文应该可以在线程之间正常工作)。

这个想法是要有一个GUID,该GUID在对我的服务器的任何请求与由于该请求而向各种Web服务发出的相应请求之间共享。我尝试同时使用MDLC和NDLC。

问题在于,即使为服务器的每个新请求正确生成了GUID,该值也只能为第一个请求正确存储,并且为所有后续请求保存空白值。

我尝试记录到数据库或文件中。如果我在代码中添加一个断点,或者在日志记录方法周围的任何地方添加System.Threading.Sleep,问题似乎都能解决。同样奇怪的是,我可以在设置逻辑上下文中的值的方法之前或之后添加Sleep,并且无论哪种方法都可以正常工作。删除睡眠/断点将导致它再次中断。

我正在使用NLog v4.5.2。

记录模块:

using System;
using System.Web;
using NLog;

namespace Shift.Stardust.Engine.Modules
{
    public class LoggingHttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += HandleBeginRequest;
        }

        public void Dispose()
        {
        }

        private void HandleBeginRequest(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(500);
            var guid = Guid.NewGuid().ToString();
            NestedDiagnosticsLogicalContext.Push(guid);
        }
    }
}

在HandleBeginRequest中的任意位置放置一个断点会产生正确的输出。添加System.Threading.Thread.Sleep(500)的方法类似。自然,我不想在代码中添加这样的行只是为了解决此问题。

NLog配置:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="c:\temp\nlog-internal.txt" internalLogLevel="Trace">
  <variable name="logDirectory" value="${basedir}/logs"/>
  <targets>
    <target name="asyncdatabase"
            xsi:type="AsyncWrapper"
            queueLimit="5000"
            overflowAction="Block">
        <target xsi:type="Database"
                connectionStringName="ConnectionStringHere"
                keepConnection="true">
            <commandText>[db].[P_Log_Insert] @CreateDate, @ApplicationName, @MachineName, @LoggerName, @LogLevel, @Message, @Exception, NULL, @EngineSessionId, @CorrelationId</commandText>
            <parameter name="@CreateDate" layout="${date}"/>
            <parameter name="@ApplicationName" layout="${appsetting:name=Shift.Stardust.ApplicationName}"/>
            <parameter name="@MachineName" layout="${machinename}"/>
            <parameter name="@LoggerName" layout="${logger}"/>
            <parameter name="@LogLevel" layout="${level}"/>
            <parameter name="@Message" layout="${message}"/>
            <parameter name="@Exception" layout="${exception:format=tostring}"/>
            <parameter name="@EngineSessionId" layout="${aspnet-sessionid}"/>
            <parameter name="@CorrelationId" layout="${ndlc}"/>
        </target>
    </target>
  </targets>
  <rules>
    <logger name="Http.*" minlevel="Info" writeTo="asyncdatabase" final="true" />
  </rules>
</nlog>

我希望每个传入请求都有一个不同的CorrelationID,但这仅对第一个请求成立。后续的所有值都有一个空字符串作为值。

1 个答案:

答案 0 :(得分:2)

对于这种情况,我认为最好写入HTTP上下文。

例如

HttpContext.Current.Items["myvariable"] = 123;

和用法:

${aspnet-item:variable=myvariable} - produces "123"

请参见docs

为此,您需要使用软件包NLog.Web(ASP.NET非核心)。

注意:ASP.NET Core的使用应使用NLog.Web.AspNetCore而不是NLog.Web