MVC Core中AddLogging配置LoggerFilterOptions及自定义ILogger问询
LoggerFilterOptions in a Custom ILogger Implementation in ASP.NET Core Let's break down exactly how you can work with LoggerFilterOptions when building your own custom logger or logger provider in ASP.NET Core. I know you're already familiar with how AddConfiguration binds your Logging config section to this options object—now let's dig into the implementation details for your custom logger.
1. Inject LoggerFilterOptions into Your Custom Provider/Logger
First off, when you call AddLogging, the framework automatically registers LoggerFilterOptions as a singleton in the DI container. That means you can directly inject it into your custom logger provider's constructor, then pass it along to your logger instances.
Here's a simple example of a custom provider that uses this:
public class MyCustomLoggerProvider : ILoggerProvider { private readonly LoggerFilterOptions _filterOptions; private readonly ConcurrentDictionary<string, MyCustomLogger> _loggers = new(); // Inject the pre-configured LoggerFilterOptions via constructor public MyCustomLoggerProvider(LoggerFilterOptions filterOptions) { _filterOptions = filterOptions; } public ILogger CreateLogger(string categoryName) { return _loggers.GetOrAdd(categoryName, name => new MyCustomLogger(name, _filterOptions)); } public void Dispose() => _loggers.Clear(); }
Then your custom logger can use the options to handle log filtering correctly:
public class MyCustomLogger : ILogger { private readonly string _categoryName; private readonly LoggerFilterOptions _filterOptions; public MyCustomLogger(string categoryName, LoggerFilterOptions filterOptions) { _categoryName = categoryName; _filterOptions = filterOptions; } public IDisposable BeginScope<TState>(TState state) => NullScope.Instance; public bool IsEnabled(LogLevel logLevel) { // Use the built-in filter logic from LoggerFilterOptions // First check if a custom filter delegate exists (from config or code) var filterResult = _filterOptions.Filter?.Invoke(_categoryName, logLevel); // Fall back to the minimum level if no filter applies return filterResult ?? logLevel >= _filterOptions.MinLevel; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (!IsEnabled(logLevel)) return; // Your custom logging logic here (write to file, external service, etc.) var logMessage = formatter(state, exception); Console.WriteLine($"[Custom Logger] {_categoryName} | {logLevel}: {logMessage}"); } }
2. Understand How LoggerFilterOptions Maps to Your Config
When you call AddConfiguration(configuration.GetSection("Logging")), the framework parses your config into LoggerFilterOptions properties:
MinLevel: Sets the default minimum log level for all categories (defaults toInformationif not specified).Filter: A delegate that applies category-specific rules (like theMicrosoft.AspNetCore: Warningrule in typical appsettings).
For example, this config:
{ "Logging": { "LogLevel": { "Default": "Information", "MyApp.Services": "Debug" } } }
Gets translated into a filter delegate that returns true for Debug+ levels in MyApp.Services, and Information+ for everything else. Your custom logger's IsEnabled method will automatically respect these rules when using the Filter delegate.
3. Dynamic Filter Updates (Optional)
If you need to adjust log levels at runtime (without restarting the app), you can resolve LoggerFilterOptions from DI and modify its properties directly. For example, in an admin controller:
[ApiController] [Route("admin/logging")] public class LoggingAdminController : ControllerBase { private readonly LoggerFilterOptions _filterOptions; public LoggingAdminController(LoggerFilterOptions filterOptions) { _filterOptions = filterOptions; } [HttpPost("set-min-level")] public IActionResult SetGlobalMinLevel(LogLevel newLevel) { // Wrap in a lock if you're modifying this from multiple threads lock (_filterOptions) { _filterOptions.MinLevel = newLevel; } return Ok("Global log level updated"); } }
Just make sure your IsEnabled method checks the options every time (don't cache the result) so it picks up changes immediately.
4. Key Best Practices
- Thread Safety:
LoggerFilterOptionsisn't thread-safe by default. If you're modifying it at runtime, use locks or thread-safe wrappers to prevent race conditions. - Leverage Built-In Logic: Don't reimplement category-based filtering yourself—let the
Filterdelegate handle it. It already correctly applies your config rules. - Avoid Caching
IsEnabledResults: Always checkIsEnabledright before writing a log entry, especially if you might update filters dynamically.
内容的提问来源于stack exchange,提问作者Henrik Poulsen

