无需新建自定义ILogger,能否为不同参数类型注册格式化器?
.NET日志系统:无需自定义ILogger即可注册类型专属格式化器
完全可以在不创建全新ILogger类型的前提下,为特定参数类型注册自定义格式化逻辑,替代默认的ToString()行为。针对你提到的Protobuf IMessage类型场景,有几种可行的实现方式:
1. 全局注册类型专属格式化器(.NET 6+)
通过日志提供者的配置扩展,为所有IMessage类型参数应用统一格式化逻辑,最适合全局场景:
步骤1:实现自定义格式化逻辑
public static class ProtobufFormatHelper { // 自定义Protobuf消息格式化逻辑,比如序列化为带缩进的文本或JSON public static string FormatProtobufMessage(IMessage message) { // 使用Protobuf自带的文本格式化(需引用Google.Protobuf NuGet包) return message.ToString(Google.Protobuf.TextFormattingIndented); // 或者序列化为JSON:JsonFormatter.Default.Format(message) } }
步骤2:扩展日志提供者的ValueFormatter
以常用的JSON控制台日志为例,注册全局格式化器:
var builder = WebApplication.CreateBuilder(args); // 配置日志,替换默认的ValueFormatter builder.Logging.AddJsonConsole(options => { options.FormatterOptions.ValueFormatter = new CustomProtobufValueFormatter(); }); // 自定义ValueFormatter,拦截IMessage类型 public class CustomProtobufValueFormatter : JsonValueFormatter { protected override void WriteValue(Utf8JsonWriter writer, object? value, JsonValueFormatterOptions options) { if (value is IMessage protoMessage) { writer.WriteStringValue(ProtobufFormatHelper.FormatProtobufMessage(protoMessage)); return; } // 其他类型沿用默认格式化逻辑 base.WriteValue(writer, value, options); } }
配置完成后,所有通过logger.Log*方法传入的IMessage参数,都会自动使用你定义的格式化逻辑,无需修改原有日志调用代码。
2. 封装强类型日志扩展方法
如果希望仅在特定场景下使用自定义格式化,可以封装扩展方法,利用LoggerMessage.Define实现高效的强类型日志:
public static class ProtobufLoggerExtensions { private static readonly Action<ILogger, IMessage, Exception?> _logProtobufDebug = LoggerMessage.Define<IMessage>( LogLevel.Debug, new EventId(101, "ProtobufDebug"), "Debug: Protobuf message content - {Message}"); public static void LogProtobufDebug(this ILogger logger, IMessage message) { _logProtobufDebug(logger, message, null); } }
使用时直接调用扩展方法即可:
logger.LogProtobufDebug(myProtobufMessage);
3. 针对特定模板格式的格式化器
如果需要在日志模板中指定格式化规则(比如{MyProp:Protobuf}),可以实现ICustomFormatter:
public class ProtobufFormatter : ICustomFormatter, IFormatProvider { public object? GetFormat(Type? formatType) { return formatType == typeof(ICustomFormatter) ? this : null; } public string Format(string? format, object? arg, IFormatProvider? formatProvider) { if (arg is IMessage message && format?.Equals("Protobuf", StringComparison.OrdinalIgnoreCase) == true) { return ProtobufFormatHelper.FormatProtobufMessage(message); } // 其他类型使用默认ToString() return arg?.ToString() ?? string.Empty; } }
调用时需要传递格式化器实例:
logger.LogDebug(new ProtobufFormatter(), "Message: {MyProp:Protobuf}", myProtobufMessage);
内容的提问来源于stack exchange,提问作者Roger Johansson
相关产品推荐
相关产品推荐

