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

Serilog写入Azure表存储:需将类字段映射为独立列

如何用Serilog将对象的每个字段单独存储到Azure Table Storage的列中

我来帮你解决这个问题——默认情况下,Serilog的Azure Table Storage sink会把整个对象序列化到Data列或者渲染到RenderedMessage里,要把SimpleTransation的每个字段拆成独立列,咱们可以通过结构化日志配置和自定义列映射来实现,具体步骤如下:

1. 确认依赖与类结构

首先确保你已经安装了Serilog.Sinks.AzureTableStorage NuGet包,然后你的SimpleTransation类结构大概是这样(方便后续映射):

public class SimpleTransation
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Type { get; set; }

    public SimpleTransation(int id, string title, string type)
    {
        Id = id;
        Title = title;
        Type = type;
    }
}

2. 方法一:用propertyColumns快速映射字段

这是最简单的方式,直接在Logger配置里指定要提取的对象属性路径,Sink会自动创建对应的列:

// 替换成你的Azure存储连接字符串
var storage = CloudStorageAccount.Parse("你的Azure存储账户连接字符串");

var logger = new LoggerConfiguration()
    .WriteTo.AzureTableStorage(
        storage,
        restrictedToMinimumLevel: LogEventLevel.Information,
        tableName: "LogStorage",
        // 指定要提取的对象属性路径,这里的Transaction是日志时给对象起的名称
        propertyColumns: new[] { "Transaction.Id", "Transaction.Title", "Transaction.Type" }
    )
    .CreateLogger();

// 关键:用结构化日志的方式传入对象,给对象命名为Transaction
var _simpleTransation = new SimpleTransation(99, "some title9", "type99");
logger.Information("记录交易信息 {Transaction}", _simpleTransation);

这样配置后,Azure Table Storage里就会多出Transaction_Id、Transaction_Title、Transaction_Type这几个独立列,分别存储对应字段的值。

3. 方法二:自定义ITableEntityFactory实现完全控制

如果需要更灵活的列命名、类型处理或者额外逻辑,可以自定义实体工厂,完全控制日志实体的生成:

public class CustomLogEntityFactory : ITableEntityFactory
{
    public ITableEntity CreateEntity(LogEvent logEvent, string partitionKey, string rowKey)
    {
        // 初始化基础日志实体
        var entity = new DynamicTableEntity(partitionKey, rowKey)
        {
            Timestamp = logEvent.Timestamp,
            Properties =
            {
                { "LogLevel", EntityProperty.GeneratePropertyForString(logEvent.Level.ToString()) },
                { "LogMessage", EntityProperty.GeneratePropertyForString(logEvent.MessageTemplate.Text) }
            }
        };

        // 从日志属性中提取SimpleTransation对象
        if (logEvent.Properties.TryGetValue("Transaction", out var transactionValue) &&
            transactionValue is StructureValue transaction)
        {
            // 遍历对象的每个属性,创建独立列
            foreach (var prop in transaction.Properties)
            {
                // 可以自定义列名,比如这里加前缀避免冲突
                entity.Properties.Add($"Trans_{prop.Name}", EntityProperty.GeneratePropertyForObject(prop.Value.Value));
            }
        }

        return entity;
    }
}

然后在Logger配置中指定这个自定义工厂:

var logger = new LoggerConfiguration()
    .WriteTo.AzureTableStorage(
        storage,
        restrictedToMinimumLevel: LogEventLevel.Information,
        tableName: "LogStorage",
        tableEntityFactory: new CustomLogEntityFactory()
    )
    .CreateLogger();

// 同样用结构化日志方式传入对象
var _simpleTransation = new SimpleTransation(99, "some title9", "type99");
logger.Information("记录交易信息 {Transaction}", _simpleTransation);

这种方式你可以自由调整列名、处理特殊类型,甚至添加额外的自定义列。

重要注意事项

  • 一定要用结构化日志语法({PropertyName})传入对象,而不是直接拼接字符串,这样Serilog才能识别对象的属性并进行映射。
  • Azure Table Storage的列名有规则:不能包含\ / # ?等特殊字符,长度不能超过255个字符,自定义列名时要符合这些要求。
  • 如果对象包含复杂嵌套属性,需要在propertyColumns里写完整路径(比如Transaction.User.Id),或者在自定义工厂里递归处理嵌套结构。

内容的提问来源于stack exchange,提问作者Bashar Abu Shamaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:04:52