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

如何在Serilog ExpressionTemplate中用#each输出列表属性JSON

Serilog ExpressionTemplate 自定义JSON日志时遍历列表子属性报错的解决方法

问题描述

尝试使用Serilog ExpressionTemplate生成自定义JSON日志,希望输出List参数的子属性,于是在模板中使用#each循环遍历列表项并输出其属性,但运行时抛出`System.ArgumentException: Syntax error (line 1, column 103): unexpected ``#```。若注释掉循环部分,日志仅输出列表项的对象类型名。

代码示例

using Serilog;
using Serilog.Debugging;
using Serilog.Templates;

namespace SerilogExpressionTemplateObjectExpansion
{
    internal class Program
    {
        static void Main(string[] args)
        {
            SelfLog.Enable(Console.Error);

            using var log = new LoggerConfiguration()
                .Enrich.WithProperty("Application", "Example")
                .WriteTo.Console(new ExpressionTemplate(
                    "{ {@t: UtcDateTime(@t), @mt, @l: if @l = 'Information' then undefined() else @l, " +
                    " test_results: [" +
                    "    {#each result in @p.test_results}" +
                    "      { name: result.Name, isInStock: {result.IsInStock} }," +
                    "    {#end}" +
                    "  ]" +
                    " @x, ..@p} }\n"))
                .CreateLogger();

            var sut = new SomeListOfItems
            {
                Items = new List<SomeItem>
                {
                    new SomeItem { Name = "Tea", IsInStock = true },
                    new SomeItem { Name = "Coffee", IsInStock = false }
                }
            };
            
            log.ForContext<Program>()
                .Warning("List of results {test_results}", sut.Items);
        }
    }

    internal class SomeItem
    {
        public string Name { get; set; }
        public bool IsInStock { get; set; }
    }

    internal class SomeListOfItems
    {
        public List<SomeItem> Items { get; set; } = new List<SomeItem>();
    }
}

注释循环后的输出

{"@t":"2024-09-19T14:22:47.0555253Z","@mt":"List of results {test_results}","@l":"Warning","test_results":["SerilogExpressionTemplateObjectExpansion.SomeItem","SerilogExpressionTemplateObjectExpansion.SomeItem"],"SourceContext":"SerilogExpressionTemplateObjectExpansion.Program","Application":"Example"}

错误原因

误用了模板语法:Serilog ExpressionTemplate采用Serilog表达式语言,并不支持#each这类类似Handlebars的循环语法,这是触发语法错误的直接原因。默认情况下,Serilog会将复杂对象序列化为类型名称,因此注释循环后仅能看到类的全名。

解决方案

要正确遍历列表并输出子属性,需使用Serilog表达式的enumerate()函数,结合投影语法生成结构化列表内容。修改ExpressionTemplate的定义,替换掉原有的#each循环:

修改后的核心代码

using var log = new LoggerConfiguration()
    .Enrich.WithProperty("Application", "Example")
    .WriteTo.Console(new ExpressionTemplate(
        "{ {@t: UtcDateTime(@t), @mt, @l: if @l = 'Information' then undefined() else @l, " +
        " test_results: enumerate(@p.test_results, x => { name: x.Name, isInStock: x.IsInStock })," +
        " @x, ..@p} }\n"))
    .CreateLogger();

说明

  • enumerate(collection, projection):遍历集合中的每个元素,通过第二个参数的投影函数生成新的结构化对象
  • 投影函数中直接访问元素的子属性(x.Name、x.IsInStock),即可生成包含子属性的JSON结构
  • 移除原循环中多余的逗号,避免JSON格式错误

正确输出示例

{"@t":"2024-09-19T14:22:47.0555253Z","@mt":"List of results {test_results}","@l":"Warning","test_results":[{"name":"Tea","isInStock":true},{"name":"Coffee","isInStock":false}],"SourceContext":"SerilogExpressionTemplateObjectExpansion.Program","Application":"Example"}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:27:24