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

Serilog无法解构集合内的匿名复杂对象问题求助

解决Serilog无法解构Dictionary<string, object>中复杂对象的问题

当使用Serilog日志Dictionary<string, object>类型的属性时,如果其中包含反序列化后的复杂对象(比如Newtonsoft.Json的JObject或System.Text.Json的JsonElement),Serilog默认无法正确解构,会输出类似[ [[]], [[]] ]的异常结果。以下是几种可行的解决方案:

方案1:自定义Serilog解构器

通过实现IDestructuringPolicy,让Serilog能识别并正确解构JObject或JsonElement类型。

针对Newtonsoft.Json的JObject

创建解构器类:

using Serilog.Core;
using Serilog.Events;
using Newtonsoft.Json.Linq;

public class JObjectDestructuringPolicy : IDestructuringPolicy
{
    public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
    {
        if (value is JObject jObject)
        {
            var properties = jObject.Properties()
                .Select(p => new LogEventProperty(p.Name, propertyValueFactory.CreatePropertyValue(p.Value, destructureObjects: true)));
            result = new StructureValue(properties);
            return true;
        }
        result = null;
        return false;
    }
}

注册到Serilog配置:

Log.Logger = new LoggerConfiguration()
    .Destructure.With<JObjectDestructuringPolicy>()
    // 其他配置(如输出目标、格式化器等)
    .CreateLogger();

针对System.Text.Json的JsonElement

创建解构器类:

using Serilog.Core;
using Serilog.Events;
using System.Text.Json;

public class JsonElementDestructuringPolicy : IDestructuringPolicy
{
    public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
    {
        if (value is JsonElement element && element.ValueKind == JsonValueKind.Object)
        {
            var properties = element.EnumerateObject()
                .Select(p => new LogEventProperty(p.Name, propertyValueFactory.CreatePropertyValue(p.Value, destructureObjects: true)));
            result = new StructureValue(properties);
            return true;
        }
        result = null;
        return false;
    }
}

注册到Serilog配置:

Log.Logger = new LoggerConfiguration()
    .Destructure.With<JsonElementDestructuringPolicy>()
    // 其他配置
    .CreateLogger();

方案2:修改反序列化配置,将复杂对象转为ExpandoObject

通过调整Web API的反序列化规则,让JSON中的复杂对象直接转为ExpandoObject(Serilog原生支持解构该类型)。

使用Newtonsoft.Json

在Program.cs/Startup.cs中配置:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        // 添加ExpandoObject转换器,将复杂对象转为ExpandoObject
        options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.ExpandoObjectConverter());
    });

使用System.Text.Json

在Program.cs/Startup.cs中配置:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonConverter<object>(
            (reader, typeToConvert, options) => JsonSerializer.Deserialize<System.Dynamic.ExpandoObject>(reader, options),
            (writer, value, options) => JsonSerializer.Serialize(writer, value, options)
        ));
    });

方案3:手动处理对象后再日志输出

如果只需要局部处理,可以在日志前将JObject/JsonElement转为Serilog可识别的类型:

[HttpPost("information")]
public void LogInformation([FromBody] LogRequest requestData)
{
    var processedMetaData = requestData.AdditionalMetaData?.ToDictionary(
        k => k.Key,
        v => v.Value switch
        {
            JObject jObj => jObj.ToObject<dynamic>(),
            JsonElement elem => JsonSerializer.Deserialize<dynamic>(elem.GetRawText()),
            _ => v.Value
        }
    );

    var logData = new
    {
        requestData.LogMessage,
        AdditionalMetaData = processedMetaData
    };

    logger.Information("{@logData}", logData);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:10:05