如何在Serilog结构化日志中强制特定场景下统一使用指定通用属性名称
Great question—locking down consistent property names like {Username} across multiple classes is critical for keeping your structured logs clean, making them easier to query in tools like Elasticsearch or Splunk, and avoiding messy inconsistencies down the line. Here are three practical ways to enforce this in Serilog:
1. Create Strongly-Typed Logging Extension Methods (Best for Simplicity & Compile-Time Safety)
The most straightforward approach is to wrap your disk quota log calls in a dedicated extension method. This removes any chance of developers using incorrect property names, since they won’t be writing the message template directly.
Here’s how to implement it:
using Serilog; using Serilog.Events; using Serilog.Parsing; public static class DiskQuotaLoggingExtensions { // Pre-parsed message template to avoid repeated parsing overhead private static readonly MessageTemplate _quotaExceededTemplate = MessageTemplateParser.Parse("Disk Quota {DiskQuota} exceeded by user {Username}"); public static void LogDiskQuotaExceeded(this ILogger logger, int diskQuota, string username) { // Write the log using the fixed template and required parameters logger.Write(LogEventLevel.Information, _quotaExceededTemplate, diskQuota, username); } }
Now, instead of writing raw log calls, all classes use this extension method:
// Correct usage log.LogDiskQuotaExceeded(100, "User1"); // No way to write this anymore—compiler will throw an error if you try to use {User} or {UserID} // log.Info("Disk Quota {DiskQuota} exceeded by user {User}", 100, "User2");
This approach also makes it easy to update the log message template later—you only need to change it in one place, and all calls automatically pick up the update.
2. Use a Custom Roslyn Analyzer (For Compile-Time Enforcement Across Your Team)
If you want to enforce this as a team-wide code rule (and catch mistakes before they even run), you can build a custom Roslyn analyzer. This will scan your codebase for log messages related to disk quota limits and flag any that use invalid property names like {User} or {UserID}.
The core logic of the analyzer would:
- Detect log method calls (like
Log.Information) that contain the phrase "Disk Quota exceeded by user" in their message template. - Parse the message template to check for user-related properties.
- Throw a compile-time warning or error if any property other than
{Username}is used for the user identifier.
While building a Roslyn analyzer requires some familiarity with the .NET code analysis APIs, it’s a powerful way to enforce logging standards at scale.
3. Runtime Validation with a Log Event Enricher (As a Safety Net)
If you want a runtime check to catch any accidental violations (even if someone bypasses the extension method), you can create a custom Serilog enricher that validates log events before they’re written.
Here’s an example:
using Serilog.Core; using Serilog.Events; public class DiskQuotaPropertyValidator : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { // Check if the log event is related to disk quota exceeded if (logEvent.MessageTemplate.Text.Contains("Disk Quota exceeded by user", StringComparison.OrdinalIgnoreCase)) { // Ensure the {Username} property exists if (!logEvent.Properties.ContainsKey("Username")) { // In development, throw an exception to catch the issue immediately #if DEBUG throw new InvalidOperationException("Disk quota exceeded logs must include the {Username} property."); #else // In production, log an error instead of crashing Log.Logger.Error("Invalid disk quota log detected: missing {Username} property. Message: {Message}", logEvent.MessageTemplate.Text, logEvent.RenderMessage()); #endif } // Check for invalid user property names var invalidProperties = logEvent.Properties.Keys.Where(k => k is "User" or "UserID").ToList(); if (invalidProperties.Any()) { #if DEBUG throw new InvalidOperationException($"Disk quota logs cannot use properties: {string.Join(", ", invalidProperties)}. Use {Username} instead."); #else Log.Logger.Error("Invalid disk quota log properties detected: {InvalidProperties}. Use {Username} instead.", invalidProperties, "Username"); #endif } } } }
Then register the enricher in your Serilog configuration:
Log.Logger = new LoggerConfiguration() .Enrich.With<DiskQuotaPropertyValidator>() // Add your sinks, minimum level, etc. .CreateLogger();
This acts as a safety net—any invalid logs will either crash the app (in development, so you fix it right away) or log an error (in production, so you can investigate later).
Recommendation
My top pick is the extension method approach—it’s simple, gives you compile-time safety, and keeps your logging code clean and consistent. Pair it with a Roslyn analyzer if you need to enforce the rule across a large team, and add the runtime validator as a last line of defense.
内容的提问来源于stack exchange,提问作者RJV

