You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core应用Windows本地调试启用Gelf时崩溃求助

问题分析:.NET Core本地调试启用Graylog时栈溢出,K8s环境正常

我有一个.NET Core应用,生产环境(K8s)运行正常,使用NLog将日志输出到debug.txt和Graylog。但在Windows 10本地调试时,启用Graylog目标会导致应用崩溃并抛出栈溢出错误,禁用Graylog则一切正常。已尝试更新NLog、Gelf组件,移除应用中的Newtonsoft.Json依赖,但问题仍未解决。

NLog配置片段

<target xsi:type="Gelf" name="graylog" endpoint="udp://graylogHost" facility="netcore"
        SendLastFormatParameter="true" gelfVersion="1.1">
    <parameter name="assembly" layout="${appdomain:format={1\}:cached=True}" />
    <parameter name="log-level" layout="${level:uppercase=true}" />
    <parameter name="callsite"
               layout="${callsite:className=True:fileName=False:includeSourcePath=False:methodName=True}" />
    <parameter name="threadid" layout="${threadid}" />
    <!--<parameter name="hostname" layout="${right:inner=${hostname}:length=5}"/>-->
    <parameter name="hostname" layout="${hostname}" />
    <parameter name="activityId"
               layout="${activityid:whenEmpty=${aspnet-TraceIdentifier:whenEmpty=${activity:property=TraceId}}}" />
    <parameter name="hierarchicalId"
               layout="${activity:property=Id}" />
    <parameter name="spanId"
               layout="${activity:property=SpanId}" />
    <parameter name="parentId"
               layout="${activity:property=ParentId}" />
    <parameter name="traceId"
               layout="${activity:property=TraceId}" />
</target>

错误信息

Stack overflow.
Repeat 12112 times:
--------------------------------
   at System.Reflection.Emit.InternalAssemblyBuilder.Equals(System.Object)
   at System.Reflection.Emit.InternalModuleBuilder.Equals(System.Object)
--------------------------------
   at System.Collections.Generic.ObjectEqualityComparer`1[[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].IndexOf(System.__Canon[], System.__Canon, Int32, Int32)
   at System.Array.IndexOf[[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon[], System.__Canon, Int32, Int32)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContract, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContract ByRef, System.Object ByRef)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonObjectContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(Newtonsoft.Json.JsonWriter, System.Object, System.Type)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(Newtonsoft.Json.JsonWriter, System.Object, System.Type)
   at Newtonsoft.Json.Linq.JToken.FromObjectInternal(System.Object, Newtonsoft.Json.JsonSerializer)
   at NLog.Web.AspNetCore.Targets.Gelf.GelfConverter.AddAdditionalField(System.Collections.Generic.IDictionary`2&lt;System.String,Newtonsoft.Json.Linq.JToken&gt;, System.Collections.Generic.KeyValuePair`2&lt;System.Object,System.Object&gt;)
   at NLog.Web.AspNetCore.Targets.Gelf.GelfConverter.GetGelfJson(NLog.LogEventInfo, System.String, System.String)
   at NLog.Web.AspNetCore.Targets.Gelf.GelfTarget.Write(NLog.LogEventInfo)
   at NLog.Targets.Target.Write(NLog.Common.AsyncLogEventInfo)
   at NLog.Targets.Target.Write(System.Collections.Generic.IList`1&lt;NLog.Common.AsyncLogEventInfo&gt;)
   at NLog.Targets.Target.WriteAsyncThreadSafe(System.Collections.Generic.IList`1&lt;NLog.Common.AsyncLogEventInfo&gt;)
   at NLog.Targets.Target.WriteAsyncLogEvents(System.Collections.Generic.IList`1&lt;NLog.Common.AsyncLogEventInfo&gt;)
   at NLog.Targets.Wrappers.AsyncTargetWrapper.WriteLogEventsToTarget(System.Collections.Generic.IList`1&lt;NLog.Common.AsyncLogEventInfo&gt;, System.String)
   at NLog.Targets.Wrappers.AsyncTargetWrapper.WriteLogEventsInQueue(Int32, System.String)
   at NLog.Targets.Wrappers.AsyncTargetWrapper.ProcessPendingEvents(System.Object)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.TimerQueueTimer.Fire(Boolean)
   at System.Threading.TimerQueueTimer.System.Threading.IThreadPoolWorkItem.Execute()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

原因分析

  1. 本地调试的动态程序集特性
    Windows本地调试时,.NET Core会生成InternalAssemblyBuilder/InternalModuleBuilder这类动态程序集,用于支持热重载、调试符号等功能;而K8s生产环境是发布后的静态程序集,不存在这类动态对象。当Gelf目标序列化${appdomain:format={1\}:cached=True}获取的程序集对象时,Newtonsoft.Json会遍历其内部属性,触发动态程序集的循环引用检查,反复调用Equals方法导致栈溢出。

  2. Gelf组件的Newtonsoft.Json依赖
    即使移除了应用中的Newtonsoft.Json,NLog的Gelf目标依赖的组件内部仍会引用Newtonsoft.Json。该组件在处理动态程序集对象时,循环引用检测逻辑无法正确处理InternalAssemblyBuilder的嵌套引用,最终引发栈溢出。

  3. 布局渲染器的返回类型差异
    ${appdomain:format={1\}}渲染器默认返回Assembly对象而非字符串。生产环境的静态程序集序列化不会触发循环引用,但本地调试的动态程序集则会引发问题,这就是K8s环境正常、本地调试异常的核心原因。

临时解决方案

修改assembly参数的布局,直接输出程序集名称字符串而非对象:

<parameter name="assembly" layout="${assembly-name:cached=True}" />

或者调整${appdomain}的格式化方式确保返回字符串:

<parameter name="assembly" layout="${appdomain:format={0}:cached=True}" />

内容的提问来源于stack exchange,提问作者smartdiv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:44:52