如何通过.NET SourceGenerator实现高效日志记录器性能优化?

摘要:## 前言 在现在许许多多的应用系统中,日志非常关键,它即是排查问题的强力工具,也是程序员居家旅行工作甩锅必备良品。 在团队中编码中,我们都要求对于那些会变更数据的接口、调用第三方的接口记录请求和响应参数,另外在关键
## 前言 在现在许许多多的应用系统中,日志非常关键,它即是排查问题的强力工具,也是程序员居家旅行工作甩锅必备良品。 在团队中编码中,我们都要求对于那些会变更数据的接口、调用第三方的接口记录请求和响应参数,另外在关键的代码路径记录后续可供诊断的日志信息。 如果使用了微软官方的日志记录框架Microsoft.Extensions.Logging,我们通常会像下面代码一样记录日志。 这是我们经常会遇到的日志记录场景,其中会记录一些外部传入的参数。带参数的日志会有频繁的字符串拼接必然会使用更多的内存对GC造成更大的压力。当系统处理的请求越来越多的时候,日志记录就很可能会成为瓶颈。 // 创建日志记录类,分别使用不同的方式来记录日志 var logger = LoggerFactory.Create(l => l.AddConsole()).CreateLogger(typeof(OrderLogger)); var orderLogger = new OrderLogger(logger); var member = new Member("8888","Justin Yu"); orderLogger.LogByStringInterpolation(member, DateTime.Now); orderLogger.LogByStructure(member, DateTime.Now); OrderLogger.LogBySourceGenerator(logger, member, DateTime.Now); /// <summary> /// 会员 /// </summary> /// <param name="MemberId">会员Id</param> /// <param name="Name">会员名</param> public record Member(string MemberId, string Name); /// <summary> /// 订单日志记录类 /// 需要使用Source Generator 所以类型为partial /// </summary> public partial class OrderLogger { private readonly ILogger _logger; public OrderLogger(ILogger logger) { _logger = logger; } /// <summary> /// 使用字符串插值记录 /// </summary> public void LogByStringInterpolation(Member member, DateTime now)=> _logger.LogInformation($"会员[{member}]在[{now:yyyy-MM-dd HH:mm:ss}]充值了一个小目标"); /// <summary> /// 使用参数化记录 /// </summary> public void LogByStructure(Member member, DateTime now) => _logger.LogInformation("会员[{Member}]在[{Now:yyyy-MM-dd HH:mm:ss}]充值了一个小目标", member, now); /// <summary> /// 使用源代码生成 /// </summary> [LoggerMessage( EventId = 0, Level = LogLevel.Information, Message = "会员[{member}]在[{Now:yyyy-MM-dd HH:mm:ss}]充值了一个小目标")] public static partial void LogBySourceGenerator(ILogger logger, Member member, DateTime now); } 然后运行一下代码看看日志记录的结果,它们都能正常的输出我们想要的日志,那么究竟性能上有什么差别呢?让我们看看第二节的内容。
阅读全文