In .NET applications, logs are a powerful tool for diagnosing problems, but too many logs can drown out critical information. This article will take you through the core methods of log filtering, allowing you to control log output precisely by level, category, and provider through configuration files, code, and third-party libraries. Whether you're troubleshooting invalid logs in Azure Functions or suppressing framework noise in production, we have practical solutions for you.
Understanding Log Levels
Log levels are the foundation of filtering. In Microsoft.Extensions.Logging, the LogLevel enum defines seven levels, ordered from lowest to highest severity:
| Level | Value | Description |
|---|---|---|
| Trace | 0 | Most detailed tracing information, may contain sensitive data, disabled by default. |
| Debug | 1 | Used for development debugging, high volume, use cautiously in production. |
| Information | 2 | Routine messages, records application flow. |
| Warning | 3 | Unexpected or risky conditions, but not causing failure. |
| Error | 4 | Current operation failed, but does not cause the entire application to fail. |
| Critical | 5 | Severe errors requiring immediate attention. |
| None | 6 | Special value indicating logs should be completely ignored. |
Source: Microsoft Learn, cnblogs
Once a level is specified, logs at that level or higher will be recorded.
Filtering via Configuration Files
Most .NET applications use appsettings.json for log filtering configuration. The Logging.LogLevel section allows you to set the minimum log level per category.
Basic Category Filtering
In appsettings.json, you can specify levels for different categories:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Default: Applies to all categories not explicitly specified.Microsoft: All categories starting withMicrosoft(e.g.,Microsoft.AspNetCore) will follow this rule.Microsoft.Hosting.Lifetime: A more specific category overrides a more general one.
Source: cnblogs, Microsoft Learn
Wildcards and Provider-Specific Configuration
Categories support wildcard patterns for more flexible filtering:
*: Matches any category.Microsoft.*: Matches all subcategories starting withMicrosoft.MyApp.Data.*: Matches all categories with the prefixMyApp.Data.
Different log providers (Console, Debug, EventSource, etc.) can have independent log level settings that override the general configuration:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Default": "Error"
}
}
}
}
Settings in Logging.{Provider}.LogLevel override those with the same name in Logging.LogLevel. The Windows EventLog provider is special; if not explicitly configured, it defaults to the Warning level.
Source: Microsoft Learn, cnblogs (C004, C005, C012)
Filtering in Code
Sometimes configuration files are not flexible enough, and dynamic filtering in code is needed. Microsoft.Extensions.Logging provides the AddFilter extension method.
Using AddFilter
AddFilter can add filtering rules by category name and log level:
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.AddFilter("*", LogLevel.Warning); // Only logs Warning and above
});
The first parameter is the category name, which supports wildcards; the second is the minimum log level. You can also add filters for specific providers:
builder.AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Debug);
Source: cnblogs (C009), Microsoft Learn
Conditional Logging: IsEnabled
Before logging, checking ILogger.IsEnabled(LogLevel) can avoid unnecessary string formatting, improving performance. However, modern log frameworks are highly optimized; for most scenarios, calling the log method directly is sufficient. Only when parameter computation is expensive should you use IsEnabled.
if (_logger.IsEnabled(LogLevel.Debug))
{
_logger.LogDebug("Processing customer with ID {CustomerId}", customerId);
}
Source: OpenTelemetry Best Practices, c-sharpcorner (C003)
Using the Microsoft.Extensions.Logging.Filter Package
To use the WithFilter extension method on ILoggerFactory, you need to install the Microsoft.Extensions.Logging.Filter package separately. This package provides classes like FilterLoggerSettings for advanced filtering configuration.
loggerFactory.WithFilter(new FilterLoggerSettings
{
{ "Microsoft", LogLevel.Warning },
{ "System", LogLevel.Warning },
{ "ToDoApi", LogLevel.Debug }
});
Source: community.dynamics.com, NuGet (C011)
Using Serilog for Filtering
Serilog is one of the most popular structured logging libraries in .NET, offering powerful filtering capabilities.
Minimum Level Override
With MinimumLevel and Override, you can set different minimum levels for different namespaces:
{
"Serilog": {
"Using": ["Serilog.Sinks.Console"],
"MinimumLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.EntityFrameworkCore": "Error"
},
"WriteTo": [{ "Name": "Console" }]
}
}
Override only further raises the level; it does not lower the globally set level.
Expression Filtering
Serilog Expressions allow filtering logs using SQL-like syntax without recompiling:
{
"Serilog": {
"Using": ["Serilog.Expressions"],
"Filter": "RequestPath like '/health%' or RequestPath = '/metrics'"
}
}
Property Filtering
You can also include or exclude logs based on log properties:
Log.Information("Order received {@Order}", order);
// Logs containing sensitive properties can be filtered out in the pipeline
Source: dash0 Practitioner's Guide, ironpdf (C002, C008)
Using NLog for Filtering
NLog is another feature-rich logging library that uses a rule-based filtering system.
Rule Configuration
In nlog.config, the logger elements under the rules node use a wildcard name attribute and specify the accepted log level range via minlevel and maxlevel:
<nlog>
<rules>
<logger name="*" minlevel="Debug" maxlevel="Info" />
<logger name="Microsoft.*" minlevel="Warning" />
</rules>
</nlog>
Matching proceeds from top to bottom; if a rule sets final="true", subsequent rules are not matched.
Source: dev.to (C006)
Using Sentry for Filtering
Sentry's .NET SDK fully respects the existing Microsoft.Extensions.Logging configuration. You can reduce noisy categories or completely disable the Sentry provider via standard MEL configuration:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
},
"Sentry": {
"LogLevel": {
"Default": "None"
}
}
}
}
Setting Logging:Sentry:LogLevel:Default to None prevents all logs from being sent through Sentry's MEL provider, but EnableLogs can still be used independently.
Source: Sentry documentation (C007)
Common Pitfalls and Troubleshooting
Serilog Filtering Issues in Azure Functions
When using Serilog in Azure Functions, some logs may still appear even if filtering rules are configured. Users have reported that despite trying various configurations, logs keep appearing. This may be due to conflicts between the Azure Functions host's own logging behavior and Serilog's configuration. The issue is discussed on GitHub (Issue #2916).
Source: GitHub Issue #2916 (C001)
Forgetting to Install the Microsoft.Extensions.Logging.Filter Package
Calling WithFilter on ILoggerFactory without installing the Microsoft.Extensions.Logging.Filter package will cause compilation errors. Ensure the package is explicitly referenced in your project.
Source: community.dynamics.com (C011)
Next Steps
- Review your current log configuration and identify sources of noise.
- Set reasonable levels (e.g.,
Warning) for framework categories likeMicrosoftinappsettings.json. - For dynamic needs, try using
AddFilteror Serilog Expressions in code. - In special environments like Azure Functions, be aware that host defaults may override filter settings.
- Monitor log volume and gradually adjust filtering rules to avoid over-filtering.
With the methods above, you can effectively control log output, making logs a "friend" rather than a "noise source" for your application.