Welcome to AutoLoggerMessage, a source generator that automatically creates LoggerMessage methods, enabling high-performance logging.
Just follow these two simple steps:
1. Install the Package from NuGet
dotnet add package stbychkov.AutoLoggerMessage
Interceptors can be enabled either for a specific project or globally by defining them in the Directory.Build.props file
<PropertyGroup>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Logging.AutoLoggerMessage</InterceptorsPreviewNamespaces>
</PropertyGroup>
Check this page for configuration options that can tweak the source generation process.
You can achieve performance boosts of up to 90% according to my benchmarks just by including this source generator in your project.
Configuration | Mean | Ratio | Allocated |
---|---|---|---|
Default implementation | 38.149 ns | 1.00 | 216 B |
Default + AutoLogger | 3.734 ns | 0.10 | - |
AutoLoggerMessage | 3.747 ns | 0.10 | - |
Take a look at benchmark page for more details.
- It supports only static
EventId
parameter. If you pass the explicitEventId
parameter, which basically no one does as far as I can tell, it generates a newEventId
and the existing one will be passed to the formatter state, but it won't be logged. This limitation comes from the originalLoggerMessage
generator as they don't support the explicit parameter ~~ yet~~. Log.Define
supports only 6 message parameters (src) so if you pass more than that, the defaultLogger.Log(*, params object[] args)
will be executed.- As this solution is based on interceptors, only .NET 8+ is supported
If something is not working as expected, you can fall back on the default implementation of ILogger extensions. To do this, call the extensions directly, for example:
logger.LogInformation("Some message"); // instead of this
LoggerExtensions.LogInformation(logger, "Some message"); // use this
In such case, the source generator will bypass the log call, ensuring you get the expected behavior.
If you require functionality from the LoggerMessage
source generator that is not supported by this library,
you can manually create your own source-generated version. Simply define your own partial class and partial method, annotated with the [LoggerMessage] attribute.
logger.LogInformation("Some message"); // instead of this
[LoggerMessage(LogLevel = LogLevel.Information, Message = "Some message")]
public partial void LogSomeMessage(); // use this
But for both scenarios, it’s recommended to report the issue, as it shouldn't happen under normal circumstances. Your feedback can help improve the library and address potential shortcomings. Thank you!
Source-generated logging is increasingly recognized as a modern and efficient approach. Check this page to see why.
But let’s be real, when you’ve got a mid-sized project, migrating to the new logging approach is not exactly a simple task. And even when starting a new project, marking every class as partial or depending on an external partial class for logging messages can feel disconnected from the code where they are actually used.
This library handles most of the heavy lifting for you, so you can spend your time doing more important things!
But I hope this is a temporary solution — maybe one day, something similar will be added to the core library. Check this discussion for updates.
This source generator searches for all logger.Log*
methods in your code and, based on their parameters, automatically
creates partial methods for LoggerMessage
. It also generates a set of interceptors to forward
the logging calls to the newly generated LoggerMessage
methods.
For more details, see the How It Works documentation
I bet you have some questions about why things are set up the way they are. Refer to the ADR files for detailed explanations of the design decisions behind this package.