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

如何在Serilog的RenderedCompactJsonFormatter中输出解构对象的转义JSON

Serilog实现结构化日志的理想输出格式方案

需求明确

我们需要用Serilog的RenderedCompactJsonFormatter输出日志时,同时达成两个目标:

  1. 结构化的Message属性保持对象解构后的层级结构
  2. @m字段中的对象内容显示为可直接复制的转义JSON字符串

核心实现思路

直接传入对象时,Serilog会自动解构对象到Message属性,但@m会输出可读的对象结构;仅传入JSON字符串则@m是转义JSON,但Message是普通字符串。要兼顾两者,需将对象序列化为JSON字符串作为日志消息,同时把原始对象通过LogContext添加为结构化属性,让Serilog自动解构对象到Message字段。

具体步骤

1. 准备JSON序列化工具(可选)

统一序列化格式,避免不同场景下JSON输出不一致:

public static class JsonUtils
{
    private static readonly JsonSerializerOptions _serializerOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false,
        IgnoreNullValues = true
    };

    public static string Serialize(object obj)
    {
        return JsonSerializer.Serialize(obj, _serializerOptions);
    }
}

2. 配置Serilog

确保使用RenderedCompactJsonFormatter输出到文件:

var builder = Host.CreateDefaultBuilder(args);
builder.UseSerilog((context, config) =>
{
    config.WriteTo.File(
        formatter: new RenderedCompactJsonFormatter(),
        path: "logs/app-.json",
        rollingInterval: RollingInterval.Day,
        retainedFileCountLimit: 7
    );
});
builder.ConfigureServices(services => services.AddHostedService<Worker>());

var host = builder.Build();
host.Run();

3. 日志记录的正确写法

通过LogContext添加结构化属性,同时将序列化后的JSON作为日志消息:

var logData = new 
{
    OrderId = 456,
    Customer = new { Name = "Alice", Email = "alice@example.com" },
    Status = "Completed"
};

// 序列化对象为JSON字符串
var logMessageJson = JsonUtils.Serialize(logData);

// 用LogContext添加结构化属性,destructureObjects设为true确保对象被解构
using (LogContext.PushProperty("Message", logData, destructureObjects: true))
{
    _logger.LogInformation(logMessageJson);
}

4. 封装扩展方法简化调用(可选)

为ILogger写扩展方法,避免重复代码:

public static class LoggerStructuredExtensions
{
    public static void LogStructuredJson<T>(this ILogger logger, LogLevel level, T data)
    {
        var jsonMessage = JsonUtils.Serialize(data);
        using (LogContext.PushProperty("Message", data, destructureObjects: true))
        {
            logger.Log(level, jsonMessage);
        }
    }

    // 快捷方法对应不同日志级别
    public static void LogStructuredJsonInfo<T>(this ILogger logger, T data)
    {
        logger.LogStructuredJson(LogLevel.Information, data);
    }

    public static void LogStructuredJsonError<T>(this ILogger logger, T data)
    {
        logger.LogStructuredJson(LogLevel.Error, data);
    }
}

调用时只需一行代码:

_logger.LogStructuredJsonInfo(logData);

输出效果验证

最终日志输出会同时满足需求:

  • @m字段:转义后的完整JSON字符串,可直接复制使用
  • Message字段:解构后的层级化对象结构,便于日志分析工具解析

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:12:43