Skip to content

Filtering log messages

Rolf Kristensen edited this page Nov 3, 2024 · 36 revisions

Log messages may be filtered via either routing or filtering.

Routing

Logging Rules is the most efficient way to perform filtering using the name of the Logger.

One can silence a noisy loggger by redirecting it to a "blackhole" by not specifying writeTo= for the logging-rule. But if also needing custom filter logic, then one needs to use a Null target.

NLog 4.5 made it possible to specify empty writeTo="", but when using older versions then Null target must be used.

<rules>
   <!-- ignore events written that are written to a logger which starts with "Namespace." -->
   <logger name="Namespace.*" minlevel="Trace" final="true" /> <!-- BlackHole that swallows everything -->
   <logger name="Namespace.*" maxLevel="Info" final="true" />  <!-- BlackHole that swallows non-critical -->
</rules>

NLog v5 introduced the FinalMinLevel-option, because MaxLevel was causing a lot of headache and confusion.

<rules>
   <!-- ignore events written that are written to a logger which starts with "Namespace." -->
   <logger name="Namespace.*" finalMinLevel="Off" /> <!-- BlackHole that swallows everything -->
   <logger name="Namespace.*" finalMinLevel="Warn" />  <!-- BlackHole that swallows non-critical -->
</rules>

Filters

With the use of <filters> then you can inspect the actual log-events and decide to ignore (blacklist) and/or allow (whitelist) the events. See also <when> filter.

e.g.

<logger name="*" writeTo="file">
  <filters defaultAction="Log">
    <when condition="length('${message}') > 100" action="Ignore" />
  </filters>
</logger>

The defaultAction-option was introduced with NLog 4.6. Before NLog 5.0 then the default value was Neutral.

Note filters gives a performance penalty, because NLog LogEventInfo objects will be allocated upfront even if discarded by filter-result.

Example in C#

The above configuration can be implemented directly in C# like this:

var config = LogManager.Configuration;

// some target
var fileTarget = new FileTarget();

// set-up rule with filter
var loggingRule = new LoggingRule("*", fileTarget);
loggingRule.FilterDefaultAction = FilterResult.Log;
loggingRule.Filters.Add(new ConditionBasedFilter()
{
    Condition = "length('${message}') > 100",
    Action = FilterResult.Ignore
});
config.LoggingRules.Add(loggingRule);

// apply config
LogManager.Configuration = config;

With NLog 5.0 then one can also do this:

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger().FilterDynamicIgnore(evt => evt.FormattedMessage?.Length > 100).WriteToFile("log.txt");
});

Global Threshold

LogManager.GlobalThreshold can be assigned a LogLevel, and then only LogEvents with same severity (or higher) will be logged.

LogManager.GlobalThreshold will overrule the configuration of logging rules. If logging rules says minLevel="Debug" then LogManager.GlobalThreshold = LogLevel.Error will still win.

if (IsProduction)
   NLog.LogManager.GlobalThreshold = NLog.LogLevel.Info;
else
   NLog.LogManager.GlobalThreshold = NLog.LogLevel.Trace;  // No global filter

Null Logger

LogManager.CreateNullLogger() will return a Logger-instance that will not generate any output.

This can be used to silence certain components without depending on the NLog-configuration.

var logger = IsProduction ? LogManager.CreateNullLogger() : LogManager.GetCurrentClassLogger();
logger.Info("No output when in production");

DEBUG build only

The .NET compiler has the ability to remove DEBUG-code when making Release-build. This means only Debug-build will give output, when using these conditional logging methods:

  • Logger.ConditionalTrace - Performs logging using NLog LogLevel.Trace
  • Logger.ConditionalDebug - Performs logging using NLog LogLevel.Debug
_logger.ConditionalDebug("DEBUG build only output");

It is shorthand of doing this:

#if DEBUG
_logger.Debug("DEBUG build only output");
#endif

Semi Dynamic Routing Rules

Routing rules are more efficient than using dynamic filters, and the performance comes from static nature of the rules. NLog 4.6.7 introduced the ability to use Layout-logic for controlling LogLevel in the logging-rules, that can be explictly refreshed.

<nlog>
   <variable name="myLevel" value="Warn" />
    <rules>
      <logger minLevel="${var:myLevel}" writeTo="file" />
    </rules>
</nlog>

Then NLog 4.6.7 allows you to do this:

#if DEBUG
LogManager.Configuration.Variables["myLevel"] = "Debug";
LogManager.ReconfigExistingLoggers(); // Explicit refresh of Layouts and updates active Logger-objects
#endif

This could be used to create a special activate-debug-mode-method. After changing the loglevel-variable as shown above, then one could schedule a timer to restore default-level to "Warn" after 5 mins.

Fully Dynamic Filtering

The Semi Dynamic Routing Rules improves the combination of NLog configuration loaded from config-file, and adjusting NLog configuration at runtime.

When NLog configuration is created at runtime alone, then one have access to even more dynamic filtering logic capabilities. Ex. by using NLog.Filters.WhenMethodFilter:

config.LoggingRules.Last().Filters.Add(new WhenMethodFilter(logEvent => ShouldIgnoreLogEvent(logEvent) ? FilterResult.Ignore : FilterResult.Log));

It is also possible to use the NLog.Config.LoggingRule constructor that specifies RuleName. Where it is possible to lookup the LoggingRule using LoggingConfiguration.FindRuleByName when needing to adjust it.

Deprecated filters

These filters are deprecated. They have been replace by the <when> filter, which exposes uses modifiable conditions for filtering log events.

Clone this wiki locally