如何配置Serilog AzureTableStorageWithProperties识别LogContext属性并生成列?
我之前在使用Serilog的Azure表存储sink时也碰到过一模一样的问题,折腾了好一会儿才找到关键所在,下面一步步帮你排查解决:
1. 确认核心配置:启用LogContext enrichment
这是最容易忽略的一步!LogContext里的属性不会自动被日志事件捕获,必须显式启用Enrich.FromLogContext(),不管你是用代码配置还是appsettings.json配置,这一步必不可少。
代码配置示例
Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() // 必须加这句! .ReadFrom.Configuration(configuration) .WriteTo.AzureTableStorageWithProperties( connectionString: "你的Azure存储连接字符串", tableName: "ApplicationLogs", // 可选:指定要生成列的属性,留空则自动包含所有LogContext属性 propertyColumns: new[] { "CameraId" } ) .CreateLogger();
appsettings.json配置示例
如果是用配置文件加载,确保Serilog节点里包含Enrich配置:
"Serilog": { "Using": [ "Serilog.Sinks.AzureTableStorage" ], "Enrich": [ "FromLogContext" ], // 关键配置 "WriteTo": [ { "Name": "AzureTableStorageWithProperties", "Args": { "connectionString": "你的Azure存储连接字符串", "tableName": "ApplicationLogs", // 可选:指定要生成列的属性,去掉则自动包含所有 "propertyColumns": [ "CameraId" ] } } ] }
2. 确保使用正确的Sink类型
一定要用AzureTableStorageWithProperties而不是基础的AzureTableStorage sink!后者不会自动将日志属性生成为表的列,只有AzureTableStorageWithProperties才支持动态属性列的功能。
3. 验证LogContext的使用方式
你的using (LogContext.PushProperty("CameraId", camera.Id))写法是对的,但要确保日志语句是在using块内部执行的:
using (LogContext.PushProperty("CameraId", camera.Id)) { // 这里的日志会带上CameraId属性 Log.Warning("Camera {CameraId} recorded unusual activity", camera.Id); } // 这里的日志不会包含CameraId属性
4. 排查版本与兼容性问题
建议升级到Serilog.Sinks.AzureTableStorage的最新稳定版,旧版本可能对LogContext的支持存在bug。可以通过NuGet包管理器或者命令行更新:
Update-Package Serilog.Sinks.AzureTableStorage
5. 验证属性是否被正确捕获
可以先临时添加一个Console sink,查看日志事件是否包含CameraId属性,以此定位问题:
Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message} {Properties:j}") .WriteTo.AzureTableStorageWithProperties(...) .CreateLogger();
如果Console输出里能看到"CameraId": "xxx",说明属性已经被捕获,问题出在Azure表存储sink的配置;如果看不到,就是Enrich或者LogContext的使用问题。
额外提示:自动包含所有属性
如果你希望LogContext里的所有属性都自动生成对应列,不需要指定propertyColumns参数,直接去掉这个配置项即可,sink会自动处理所有额外属性。
内容的提问来源于stack exchange,提问作者Farzad

