Just J
Just J

Reputation: 23

NLog multiple file target issue

I am trying to implement NLog in WPF application.

We need to have two file log target,

1) for debug or developer purpose which is going some "Infologs" folder
2) for error or exception purpose which is going to some "Errorlogs" folder in

base directory. Below is my code and configuration in nlog.config for same.

<variable name="ErrorLayout" value="${longdate} | ${logger} | ${level} | 
${message} ${exception:format=message,stacktrace:separator=/}" />
<variable name="InfoLayout" value="${longdate} | ${logger} | ${level} | 
${message}"/>

<variable name="ErrorDir" value="${basedir}/Errorlogs/${longdate}">
</variable>
<variable name="InfoDir" value="${basedir}/Infologs/${longdate}"></variable>

<target xsi:type="File" name="fileLogException" archiveEvery="Month" 
createDirs="true" lineEnding="Default" layout="${ErrorLayout}" 
fileName="${ErrorDir}.log"/>

<target xsi:type="File" name="fileLogInfo" archiveEvery="Month" 
createDirs="true" lineEnding="Default" layout="${InfoLayout}" 
fileName="${InfoDir}.log"/>


<logger name="*"  minlevel="Error" writeTo="fileLogException"/>
<logger name="*"  minlevel="Info" writeTo="fileLogInfo"/>

Expected result:

_logger.Info("Sample informational message");//This should  write to only fileLogInfo

_logger.Error("Sample error message"); //this  should write to only fileLogException

_logger.Fatal("Sample fatal error message"); //this  should write to only fileLogException

Current result:

_logger.Info() write to --> fileLogInfo

_logger.Error() & _logger.Fatal() both  write to --> fileLogInfo and fileLogException

Any help please , Thanks

Upvotes: 2

Views: 2553

Answers (2)

Flater
Flater

Reputation: 13763

There are multiple approaches here. Option 3. is the best solution for your current case, in my opinion.

1. The final attribute

(this is the same answer as Julian's)

<logger name="*"  minlevel="Error" writeTo="fileLogException" final="true"/>
<logger name="*"  minlevel="Info" writeTo="fileLogInfo"/>

Adding the attribute to fileLogException means that when a message is written to fileLogException, NLog will not look for any other logs afterwards.
Note that NLog evaluates loggers from top to bottom. final will only prevent lower loggers from receiving the same log message.

This is a solution, but it can cause issues in the future. If you remove the fileLogException (or change the order of loggers), then the content of the fileLogInfo will change (because no messages are being halted by fileLogException anymore).

When should you use this option?
When you want to intercept messages and prevent them from being added to other logs.
For your current example, this seems usable at first sight. This is mainly because you are not separating loggers based on their name. But when you start considering loggers with name requirements and not just level requirements, e.g.

<logger name="MyApplication.Repositories.*" final="true" writeTo="fileLogRepository" />
<logger name="MyApplication.Importers.*" final="true" writeTo="fileLogImport" />
<logger name="*" writeTo="fileLogAllUnloggedMessages" />

it becomes more obvious when you should and shouldn't use this. In the above example, the bottom log will catch all messages except messages which have already been logged by any previous logger (which was marked as final, of course).

2. The maxLevel attribute

Just like you've used minLevel, there is also a maxLevel attribute.

<logger name="*"  minlevel="Error" writeTo="fileLogException"/>
<logger name="*"  minlevel="Trace" maxLevel="Info" writeTo="fileLogInfo"/>

fileLogException logs all messages with a level of Error and above, whereas fileLogInfo logs all messages with a level between Trace and Info (= Trace, Debug and Info).

When should you use this option?
When you want to strictly define your logger to only ever include messages between a range of accepted log levels.

I changed the level values to prove a point, that it selects all messages with a level that's between the upper limit (maxLevel) and lower limit (minLevel).

3. The level attribute

Your fileLogException is only interested in one level of messages, Info. Therefore, you can shorten this to

<logger name="*" level="Info" writeTo="fileLogInfo"/>

When should you use this option?
When you want to strictly define your logger to only ever include messages from a single log level.

4. The levels attribute

The levels attribute allows you to explicitly specify multiple levels (comma-separated).

    <logger name="*" levels="Trace,Info,Fatal" writeTo="fileLogException"/>

When should you use this option?
When you want to strictly define your logger to only ever include messages from multiple log levels that cannot be described with a range.

E.g. If you want to log Info and Error messages, and you would use maxLevel and minLevel, then Nlog would also include all Warning messages (as that falls between Info and Error in the ordered list of log levels). However, you can exclude Warning messages by using levels="Info,Error".


All information is based on the NLog documentation

Upvotes: 3

Julian
Julian

Reputation: 36710

You need the final attribute on the first <logger> rule

<logger name="*"  minlevel="Error" writeTo="fileLogException" final="true"/>
<logger name="*"  minlevel="Info" writeTo="fileLogInfo"/>

Rules are non-final by default and so the events will be written to all loggers (from top to down), which meet the name and (min)level requirements.

For more info, see the docs

Upvotes: 0

Related Questions