Logging is a critical component in modern applications, but it can easily introduce performance overhead.
.NET 6 introduced the LoggerMessageAttribute, a feature in the Microsoft.Extensions.Logging namespace that enables source-generated, highly performant logging APIs. This approach eliminates runtime overheads like boxing and temporary allocations, making it faster than traditional logging methods.
Define logging methods as partial and static to trigger the code generator:
public static partial class Log{[LoggerMessage(EventId = 0,Level = LogLevel.Critical,Message = "Could not open socket to `{HostName}`")]public static partial void CouldNotOpenSocket(ILogger logger, string hostName);}
Logging methods can also be used in an instance context by accessing an ILogger field or primary constructor parameter:
public partial class InstanceLoggingExample(ILogger logger){[LoggerMessage(EventId = 0,Level = LogLevel.Critical,Message = "Could not open socket to `{HostName}`")]public partial void CouldNotOpenSocket(string hostName);}
Using LoggerMessageAttribute with JsonConsole formatter can produce structured logs.
In our log messages we can specify custom event names as well as utelize string formatters:
[LoggerMessage(EventId = 9,Level = LogLevel.Trace,EventName = "PropertyValueEvent")]Message = "In {City} the average property value is {Value:E}")]public static partial void PropertyValueInAustralia(ILogger logger, string city double value);
When using LoggerMessageAttribute, ensure:
partial and return void.static, the ILogger instance is required as a parameter.See this great article on Microsoft Learn which goes into more detail and usage examples: Compile-time logging source generation in .NET.