Log Filtering in Practice: A Complete Guide to Controlling Log Output in .NET

Smart AI Code2026-10-025 min read

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:

LevelValueDescription
Trace0Most detailed tracing information, may contain sensitive data, disabled by default.
Debug1Used for development debugging, high volume, use cautiously in production.
Information2Routine messages, records application flow.
Warning3Unexpected or risky conditions, but not causing failure.
Error4Current operation failed, but does not cause the entire application to fail.
Critical5Severe errors requiring immediate attention.
None6Special 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 with Microsoft (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 with Microsoft.
  • MyApp.Data.*: Matches all categories with the prefix MyApp.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

  1. Review your current log configuration and identify sources of noise.
  2. Set reasonable levels (e.g., Warning) for framework categories like Microsoft in appsettings.json.
  3. For dynamic needs, try using AddFilter or Serilog Expressions in code.
  4. In special environments like Azure Functions, be aware that host defaults may override filter settings.
  5. 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.