如何通过.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);
}
然后运行一下代码看看日志记录的结果,它们都能正常的输出我们想要的日志,那么究竟性能上有什么差别呢?让我们看看第二节的内容。
