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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: .NET 6新东西--高性能日志

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

private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
    _logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> 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<ILogger, IEnumerable<WeatherForecast>, Exception?> _logWeatherForecast =
    LoggerMessage.Define<IEnumerable<WeatherForecast>>(
        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<WeatherForecast> 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::Microsoft.Extensions.Logging.ILogger, global::System.Collections.Generic.IEnumerable<global::WebApplication1.WeatherForecast>, global::System.Exception?> __LogWeatherForecastCallback =
        global::Microsoft.Extensions.Logging.LoggerMessage.Define<global::System.Collections.Generic.IEnumerable<global::WebApplication1.WeatherForecast>>(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<global::WebApplication1.WeatherForecast> 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()方法变通解决。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
SQL 程序员
分享一个 .NET 通过监听器拦截 EF 消息写日志的详细例子
分享一个 .NET 通过监听器拦截 EF 消息写日志的详细例子
|
28天前
|
消息中间件 Linux iOS开发
.NET 高性能异步套接字库,支持多协议、跨平台、高并发
【11月更文挑战第3天】本文介绍了高性能异步套接字库在网络编程中的重要性,特别是在处理大量并发连接的应用中。重点讨论了 .NET 中的 Socket.IO 和 SuperSocket 两个库,它们分别在多协议支持、跨平台特性和高并发处理方面表现出色。Socket.IO 基于 WebSocket 协议,支持多种通信协议和跨平台运行,适用于实时通信应用。SuperSocket 则通过事件驱动的异步编程模型,实现了高效的高并发处理,适用于需要自定义协议的场景。这些库各有特点,可根据具体需求选择合适的库。
|
3月前
|
前端开发 关系型数据库 MySQL
ThingsGateway:一款基于.NET8开源的跨平台高性能边缘采集网关
ThingsGateway:一款基于.NET8开源的跨平台高性能边缘采集网关
101 2
|
4月前
|
存储 监控 算法
内存泄漏还是高性能?深度揭秘.NET垃圾回收机制
【8月更文挑战第28天】垃圾回收是.NET框架中自动化内存管理的关键机制,它通过分代收集算法自动清理不再使用的对象,简化了开发者的内存管理工作。本文深入解析了垃圾回收器的工作原理、对象内存分配策略及优化技巧,并介绍了多种监控工具,帮助提升.NET应用性能与稳定性。掌握这些知识将使开发者能够更高效地管理内存,提高应用程序的运行效率。
41 3
|
4月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
4月前
|
开发者 Apache 程序员
揭秘Apache Wicket:页面生命周期背后的神秘力量!
【8月更文挑战第31天】李工是一位热爱Web开发的程序员,近日在技术博客上分享了他对Apache Wicket框架的学习心得,特别是页面生命周期的理解。他认为掌握Wicket页面生命周期对于开发富交互式Web应用至关重要。他通过一个简单的计数器应用示例,详细解释了Wicket的组件化设计理念以及页面和组件在生命周期中的变化。
48 0
|
4月前
|
存储 测试技术 C#
Blazor WebAssembly 开启离线应用开发新时代!C# 与.NET 助力,打造高性能跨平台新体验!
【8月更文挑战第31天】在互联网快速发展的今天,用户对Web应用体验的要求日益提高,尤其在无网络环境下使用应用的需求愈发明显。Blazor WebAssembly 应运而生,它基于 WebAssembly 技术,允许开发者利用 C# 和 .NET 构建交互式 Web 应用,无需服务器支持即可在浏览器中运行,从而实现离线使用。Blazor WebAssembly 具有使用熟悉的技术栈、高性能、离线支持以及跨平台等优势。开发者可通过安装开发工具、创建项目、编写代码、调试测试及发布应用几个步骤来进行开发。这为离线应用开发开启了新篇章。
84 0
|
4月前
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
|
4月前
|
开发框架 .NET API
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
196 0
|
4月前
|
监控 程序员 数据库
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子
分享一个 .NET Core Console 项目中应用 NLog 写日志的详细例子