When it comes to logging, people will think of log4net Net, you will think of ILogger, which is NET, the following code is NET Core WebAPI project initialization code, in which ILogger is used to provide logging:
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; }
Actually In NET6, Microsoft provides us with a high-performance logging class LoggerMessage. Compared with ILogger logger and its extension method, LoggerMessage has more performance advantages. First, the ILogger logger extension method needs to convert the value type into the object, but the LoggerMessage uses static methods with strongly typed parameters and extension methods to avoid this problem. In addition, the ILogger logger and its extension methods must analyze the message template every time they write to the log. However, when the message template has been defined, the LoggerMessage only needs to analyze the template once. The usage code is as follows (modify the WebAPI project initialization code):
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);
Although LoggerMessage provides us with better logging performance, it needs to write a large number of loggermessages manually Define code, and the parameter placeholder in the formatString message template is not controlled, which may lead to parameter transmission errors. Yes NET 6, Microsoft provides Source Generator to help us automatically generate high-performance logging code. It is very simple to use. First, you need to create a partial method, and then declare the loggermessattribute attribute in the header of the partial method. The use code is as follows:
[LoggerMessage(0, LogLevel.Information, "LoggerMessageAttribute: {weatherForecasts}")] partial void LogWeatherForecast(IEnumerable<WeatherForecast> weatherForecasts); //use LogWeatherForecast(result);
After compilation, LoggerMessage automatically generates code for us:
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); } } }
In the above code, the LogWeatherForecast method directly uses the data declared in the Controller_ The logger object does not need to be passed in, and it is judged before writing to the log_ logger.IsEnabled, which avoids unnecessary log writes and further improves performance. Although loggermessagetribute can improve logging performance, it also has its disadvantages:
- Class must also be defined as partial using partial method declaration.
- The log uses the ToString() method of the parameter object. For complex types, the serialization object LogWeatherForecast(JsonSerializer.Serialize(result)) cannot be passed in the method, because it will always affect the performance, but it can be solved by defining the record class or self-defined ToString() method.