栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

.NET 6新东西--高性能日志

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.NET 6新东西--高性能日志

一提到日志记录,大家就会想到log4net,如果提到.NET中的日志记录,一定会想到ILogger,这个ILogger是.NET中常用的提供的日志记录的方式,下面的代码是.NET Core WebAPI 项目初始化的代码,其中就使用了ILogger来提供日志记录:

private readonly ILogger _logger;
public WeatherForecastController(ILogger logger)
{
    _logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable Get()
{ 
    var result =  Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        TemperatureC = Random.Shared.Next(-20, 55),
    })
    .ToArray();
    _logger.LogInformation("LogInformation: {0}", JsonSerializer.Serialize(result));
    return result;
}

其实.NET6中微软为我们提供了一个高性能日志记录类LoggerMessage。与ILogger记录器和它的扩展方法相比,LoggerMessage更具性能优势。首先ILogger记录器扩展方法需要将值类型转换到object中,但是LoggerMessage使用了带有强类型参数的静态方法以及扩展方法来避免这个问题。并且ILogger记录器及其扩展方法在每次写入日志时都必须先去分析消息模板,但是LoggerMessage在已定义消息模板的情况下,只需分析一次模板即可。使用代码如下(修改WebAPI项目初始化代码):

private static readonly Action, Exception?> _logWeatherForecast =
    LoggerMessage.Define>(
        logLevel: LogLevel.Information,
        eventId: 0,
        formatString: "LoggerMessage: {aa}");
_logWeatherForecast(_logger, result, null);

虽然LoggerMessage为我们提供了性能更好的日志记录,但它需要手工编写大量的LoggerMessage.Define代码,并且formatString消息模板中的参数占位符没有进行任何控制,可能会导致传参错误。在.NET 6中微软提供了Source Generator,来帮助我们自动生成高性能日志记录代码。使用起来很简单,首先需要创建partial方法,其次在partial方法头部声明LoggerMessageAttribute属性。使用代码如下:

[LoggerMessage(0, LogLevel.Information, "LoggerMessageAttribute: {weatherForecasts}")]
partial void LogWeatherForecast(IEnumerable weatherForecasts);
//使用
LogWeatherForecast(result);

编译后,LoggerMessage就为我们自动生成了代码:

partial class WeatherForecastController 
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.5.2210")]
    private static readonly global::System.Action, global::System.Exception?> __LogWeatherForecastCallback =
        global::Microsoft.Extensions.Logging.LoggerMessage.Define>(global::Microsoft.Extensions.Logging.LogLevel.Information, new global::Microsoft.Extensions.Logging.EventId(0, nameof(LogWeatherForecast)), "LoggerMessageAttribute: {weatherForecasts}", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true });     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.5.2210")]
    partial void LogWeatherForecast(global::System.Collections.Generic.IEnumerable weatherForecasts)
    {
        if (_logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Information))
        {
            __LogWeatherForecastCallback(_logger, weatherForecasts, null);
        }
    }
}

在上面的代码中,LogWeatherForecast方法直接使用了Controller中声明的_logger对象,不需要我们传入,并且写入日志前还判断了_logger.IsEnabled,这样就避免了不必要的日志写入,并且对性能有了进一步的提高。
使用LoggerMessageAttribute虽然可以提高日志记录性能,但它也有其缺点:

  1. 使用partial方法声明必须将类也定义成partial。
  2. 日志使用了参数对象的ToString()方法,对于复杂类型不能在方法中传入序列化对象LogWeatherForecast(JsonSerializer.Serialize(result)),因为会始终执行影响性能,但是可以通过定义成record class或自定义ToString()方法变通解决。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/904372.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号