如何为Microsoft ILogger注册ProblemDetails类型自定义格式化器?
实现自定义类型的日志序列化(无需手动调用Format)
完全可行,根据你使用的日志框架类型,通过注册自定义处理器/转换器就能实现ProblemDetails类型的自动序列化,不用每次手动调用Format方法,也不会仅输出ToString()的默认结果。
针对Microsoft.Extensions.Logging(.NET默认日志框架)
可以自定义控制台格式化器(或其他输出目标的格式化器),在其中处理ProblemDetails的序列化逻辑:
- 创建自定义格式化器类,继承
ConsoleFormatter并重写Write方法:
public class CustomConsoleFormatter : ConsoleFormatter { private readonly CustomConsoleFormatterOptions _options; public CustomConsoleFormatter(CustomConsoleFormatterOptions options) : base(nameof(CustomConsoleFormatter)) { _options = options; } public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider scopeProvider, TextWriter textWriter) { var message = logEntry.Formatter(logEntry.State, logEntry.Exception); if (logEntry.State is IEnumerable<KeyValuePair<string, object>> stateProperties) { foreach (var prop in stateProperties) { if (prop.Value is ProblemDetails pd) { message = message.Replace($"{{{prop.Key}}}", Format(pd)); } } } textWriter.WriteLine(message); } } public class CustomConsoleFormatterOptions : ConsoleFormatterOptions { }
- 在DI容器中注册自定义格式化器:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddLogging(loggingBuilder => { loggingBuilder.AddConsole(options => { options.FormatterName = nameof(CustomConsoleFormatter); }) .AddConsoleFormatter<CustomConsoleFormatter, CustomConsoleFormatterOptions>(); });
针对Serilog日志框架
Serilog提供直接的类型解构配置,为ProblemDetails注册自定义序列化逻辑即可:
Log.Logger = new LoggerConfiguration() // 注册自定义字符串格式化逻辑 .Destructure.ByTransforming<ProblemDetails>(problemDetails => Format(problemDetails)) // 若需结构化输出,可返回键值对形式的对象 // .Destructure.ByTransforming<ProblemDetails>(pd => new { pd.Title, pd.Status, pd.Detail }) .WriteTo.Console() .CreateLogger();
配置完成后,直接调用_logger.LogInformation("Found a problem {Problem}", problemDetails),Serilog会自动用你指定的逻辑序列化ProblemDetails。
注意事项
- 不建议直接重写
ProblemDetails的ToString()方法,这会影响该类型在所有场景下的字符串输出,而我们通常只需要日志里用自定义格式。 - 结构化日志场景下,优先返回键值对形式的结构化数据,方便后续日志分析工具解析。
内容的提问来源于stack exchange,提问作者Julian Birch
相关产品推荐
相关产品推荐

