Is it possible to tell dynamically NLog which target to log to?

2.2k Views Asked by At

I want to implement the AppDomain.FirstChanceException in my WPF app, for optionally logging every exception that occurs, handled or not. I don't wish to log these exceptions to the targets I have configured for NLog. Is is possible, around the time of calling Logger.Error (or whatever Logger method) to make NLog only log to one particular target?

1

There are 1 best solutions below

2
Yoh Deadfall On

It's possible, but this is not a good idea because:

  1. It's not thread safe.
  2. All loggers of the specified factory will be reconfigured.

Configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets async="true">
    <target name="file1" xsi:type="File" fileName="${basedir}/log1.txt" />
    <target name="file2" xsi:type="File" fileName="${basedir}/log2.txt" />
  </targets>
  <rules>
    <logger name="*" minlevel="Trace" writeTo="file1,file2" />
  </rules>
</nlog>

Example of a global factory configuration:

var logger = LogManager.GetCurrentClassLogger();

logger.Error("Original Configuration");

var configOrig = LogManager.Configuration;
var configTemp = LogManager.Configuration.Reload();
var rule = configTemp.LoggingRules.First(r => r.NameMatches("*"));
var target = configTemp.FindTargetByName("file2");

rule.Targets.Remove(target);

LogManager.Configuration = configTemp;
logger.Error("Temporary Configuration");

LogManager.Configuration = configOrig;
logger.Error("Original Configuration");

Example of a user created factory configuration:

var factory = new LogFactory(LogManager.Configuration);
var logger = factory.GetCurrentClassLogger();

logger.Error("Original Configuration");

var config = factory.Configuration;
var rule = config.LoggingRules.First(r => r.NameMatches("*"));
var target = config.FindTargetByName("file2");

rule.Targets.Remove(target);
factory.ReconfigExistingLoggers();
logger.Error("Temporary Configuration");

rule.Targets.Add(target);
factory.ReconfigExistingLoggers();
logger.Error("Original Configuration");

log1.txt

2015-03-16 21:46:04.5685|ERROR|ConsoleApplication.Program|Original Configuration
2015-03-16 21:46:04.5865|ERROR|ConsoleApplication.Program|Temporary Configuration
2015-03-16 21:46:04.5865|ERROR|ConsoleApplication.Program|Original Configuration

log2.txt

2015-03-16 21:45:26.4238|ERROR|ConsoleApplication.Program|Original Configuration
2015-03-16 21:45:26.4588|ERROR|ConsoleApplication.Program|Original Configuration

Soulution

The best solution of the problem is to create two factories and one logger for each factory. The factories and loggers must be initialized before you subscribe to AppDomain.FirstChanceException. Otherwise, you will have problems with thread safety if you have async operations or other threads.