Skip to content

Filtering log messages

Rolf Kristensen edited this page Oct 29, 2023 · 25 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.

By not specifying writeTo= then it act like a blackhole with almost no overhead. But if also needing custom filter logic, then one needs to use a Null target.

NLog 4.5 allows one to specify an empty writeTo=""

<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>

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 has a small performance penalty, because NLog LogEventInfo objects will be allocated 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

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