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
相关产品推荐
相关产品推荐

