Convert existing logging calls to use the LoggerMessage source generator for AOT-compatible logging with no boxing overhead and compile-time template parsing.
When to Use
- Optimizing logging performance in hot paths
- Preparing for Native AOT deployment
- Organizing scattered log messages into logical groupings
- Standardizing EventIds across the codebase
Steps
Find ILogger usages and logging calls
- Search for
ILogger field/parameter declarations
- Find all logging calls:
LogInformation, LogWarning, LogError, LogDebug, LogTrace, LogCritical
- Note the log message templates and parameters
Organize into logical groupings by domain
- Group related log messages by their functional area, eg:
LoggingValidationExtensions - validation-related logs
LoggingAuthenticationExtensions - auth-related logs
LoggingDatabaseExtensions - database-related logs
LoggingHttpExtensions - HTTP-related logs
LoggingCacheExtensions - caching-related logs
LoggingMessagingExtensions - messaging/queue-related logs
Create partial static classes with extension methods
public static partial class LoggingValidationExtensions
{
[LoggerMessage(
EventId = 1001,
Level = LogLevel.Warning,
Message = "Validation failed for {EntityType}: {Errors}")]
public static partial void ValidationFailed(
this ILogger logger, string entityType, string errors);
}
Use EventId ranges per category
- 1000-1999: Validation
- 2000-2999: Authentication
- 3000-3999: Database
- 4000-4999: HTTP
- 5000-5999: Cache
- 6000-6999: Messaging
- 7000-7999: General/Application
Replace inline logging calls with extension method calls
- Before:
_logger.LogWarning("Validation failed for {entityType}: {errors}", type, errs)
- After:
_logger.ValidationFailed(type, errs)
Verify with build
dotnet build
If build fails, review errors:
- Missing
using statements for the extension class namespace
- Parameter type mismatches
- Duplicate EventIds
Report results:
- List all created extension classes
- Show count of converted log messages per category
- Confirm build status
Key Notes
- Requires .NET 6+ - the source generator is built into the SDK
- Avoids boxing - value types are not boxed when passed to the generated methods
- Template parsed once - message template is parsed at compile time, not runtime
- Use PascalCase for placeholders -
{EntityType} not {entityType} (matching is case-insensitive, but PascalCase is the recommended convention)
- Extension methods - allows fluent
logger.MethodName() syntax
- Partial classes - required for source generator to emit the implementation
Example Conversion
Before:
_logger.LogInformation("User {UserId} logged in from {IpAddress}", userId, ip);
_logger.LogWarning("Failed login attempt for {Username}", username);
After:
// In LoggingAuthenticationExtensions.cs
public static partial class LoggingAuthenticationExtensions
{
[LoggerMessage(
EventId = 2001,
Level = LogLevel.Information,
Message = "User {UserId} logged in from {IpAddress}")]
public static partial void UserLoggedIn(
this ILogger logger, string userId, string ipAddress);
[LoggerMessage(
EventId = 2002,
Level = LogLevel.Warning,
Message = "Failed login attempt for {Username}")]
public static partial void FailedLoginAttempt(
this ILogger logger, string username);
}
// Usage
_logger.UserLoggedIn(userId, ip);
_logger.FailedLoginAttempt(username);
1---2name: dotnet-source-gen-logging3description: Converts logging to use the LoggerMessage source generator for high-performance, AOT-compatible logging. Also use when the user mentions "LoggerMessage," "logging source generator," "high-performance logging," "optimize logging," "AOT logging," or "structured logging source gen." For full AOT analysis, see dotnet-aot-analysis.4license: MIT5---67Convert existing logging calls to use the `LoggerMessage` source generator for AOT-compatible logging with no boxing overhead and compile-time template parsing.89## When to Use1011- Optimizing logging performance in hot paths12- Preparing for Native AOT deployment13- Organizing scattered log messages into logical groupings14- Standardizing EventIds across the codebase1516## Steps17181. **Find ILogger usages and logging calls**19 - Search for `ILogger` field/parameter declarations20 - Find all logging calls: `LogInformation`, `LogWarning`, `LogError`, `LogDebug`, `LogTrace`, `LogCritical`21 - Note the log message templates and parameters22232. **Organize into logical groupings by domain**24 - Group related log messages by their functional area, eg:25 - `LoggingValidationExtensions` - validation-related logs26 - `LoggingAuthenticationExtensions` - auth-related logs27 - `LoggingDatabaseExtensions` - database-related logs28 - `LoggingHttpExtensions` - HTTP-related logs29 - `LoggingCacheExtensions` - caching-related logs30 - `LoggingMessagingExtensions` - messaging/queue-related logs31323. **Create partial static classes with extension methods**33 ```csharp34 public static partial class LoggingValidationExtensions35 {36 [LoggerMessage(37 EventId = 1001,38 Level = LogLevel.Warning,39 Message = "Validation failed for {EntityType}: {Errors}")]40 public static partial void ValidationFailed(41 this ILogger logger, string entityType, string errors);42 }43 ```44454. **Use EventId ranges per category**46 - 1000-1999: Validation47 - 2000-2999: Authentication48 - 3000-3999: Database49 - 4000-4999: HTTP50 - 5000-5999: Cache51 - 6000-6999: Messaging52 - 7000-7999: General/Application53545. **Replace inline logging calls with extension method calls**55 - Before: `_logger.LogWarning("Validation failed for {entityType}: {errors}", type, errs)`56 - After: `_logger.ValidationFailed(type, errs)`57586. **Verify with build**59 ```bash60 dotnet build61 ```62637. **If build fails**, review errors:64 - Missing `using` statements for the extension class namespace65 - Parameter type mismatches66 - Duplicate EventIds67688. **Report results**:69 - List all created extension classes70 - Show count of converted log messages per category71 - Confirm build status7273## Key Notes7475- **Requires .NET 6+** - the source generator is built into the SDK76- **Avoids boxing** - value types are not boxed when passed to the generated methods77- **Template parsed once** - message template is parsed at compile time, not runtime78- **Use PascalCase for placeholders** - `{EntityType}` not `{entityType}` (matching is case-insensitive, but PascalCase is the recommended convention)79- **Extension methods** - allows fluent `logger.MethodName()` syntax80- **Partial classes** - required for source generator to emit the implementation8182## Example Conversion8384Before:85```csharp86_logger.LogInformation("User {UserId} logged in from {IpAddress}", userId, ip);87_logger.LogWarning("Failed login attempt for {Username}", username);88```8990After:91```csharp92// In LoggingAuthenticationExtensions.cs93public static partial class LoggingAuthenticationExtensions94{95 [LoggerMessage(96 EventId = 2001,97 Level = LogLevel.Information,98 Message = "User {UserId} logged in from {IpAddress}")]99 public static partial void UserLoggedIn(100 this ILogger logger, string userId, string ipAddress);101102 [LoggerMessage(103 EventId = 2002,104 Level = LogLevel.Warning,105 Message = "Failed login attempt for {Username}")]106 public static partial void FailedLoginAttempt(107 this ILogger logger, string username);108}109110// Usage111_logger.UserLoggedIn(userId, ip);112_logger.FailedLoginAttempt(username);113```