Can I use two different layouts in one target in NLog? - nlog

I have two layouts in nlog.config. once is Default layout and other one is ErrorLayout in which have additional properties.
the problem is i want to add target and i want to use both layout for LogLevel.Error i have to use ErrorLayout and for the other levels i have to use DefaultLayout. i don't want to create two target because two targets creating two different file and store logs into it.
but i want to both layout into one target.
can I able to do that? How ?
can anyone help me to do this ?

Another option is you use two targets, targeting the same file. If you don't enable keepfileopen, then this is also a good solution.
For example:
<nlog>
<targets>
<target type="file" name="erp" layout="${message}" fileName="log-${shortdate}.log" />
<target type="file" name="erp-error" layout="${message} ${exception:format=tostring}" fileName="log-${shortdate}.log" />
</targets>
<rules>
<logger name="*" minLevel="Error" writeTo="erp-error" final="true" /> <!-- after match events won't be processed futher due to the final attribute -->
<logger name="*" minLevel="Debug" writeTo="erp" />
</rules>
</nlog>

Right now your DefaultLayout and ErrorLayout are quite simple, so you can just do this:
<nlog>
<variable name="DefaultLayout" value="${message}" />
<variable name="ErrorLayout" value="${message} ${exception:format=tostring}" />
<variable name="DynamicLayout= value="${when:when=level<=LogLevel.Info:inner=${DefaultLayout}:else=${ErrorLayout}}" />
<targets>
<target type="file" name="erp" layout="${DynamicLayout}" fileName="log-${shortdate}.log" />
</targets>
<rules>
<logger name="*" minLevel="Debug" writeTo="erp" />
</rules>
</nlog>
See also https://github.com/nlog/NLog/wiki/When-Layout-Renderer
Notice NLog might perform poorly if you include heavy layoutrenders in the ErrorLayout. Ex. like ${callsite}

Related

NLog file target - best performance for logging log files for Splunk Forwarder and avoid locks?

What's the best performance way of writing log files for Splunk forwarder (that monitors a folder and removes the files and puts them into Splunk)?
<target name="jsonfile" xsi:type="File" fileName="${gdc:logDirectory}/${gdc:environment}/${longdate}.json" >
<layout xsi:type="JsonLayout">
<attribute name="time" layout="${date:format=O}" />
<attribute name="message" layout="${message}" />
<attribute name="logger" layout="${logger}"/>
<attribute name="level" layout="${level}"/>
</layout>
</target>
Creates files like:
2021-08-25 18_37_45.9420.json
...
But that would mean a lot of files (every millisecond fraction). Plus if there are a lot of log activity, each log file could have more than one record (and possibly fight with the Forwarder for file locks).
I could even add a guid in the end of the file name so that I'm sure that only record logs per file, but again, that's a lot of files being created.
But if log fewer times (every second):
<target name="jsonfile" xsi:type="File"
fileName="${gdc:logDirectory}/${gdc:environment}/${date:format=yyyy-MM-dd_HH-mm-ss}.json"
<layout xsi:type="JsonLayout">
<attribute name="time" layout="${date:format=O}" />
<attribute name="message" layout="${message}" />
<attribute name="logger" layout="${logger}"/>
<attribute name="level" layout="${level}"/>
</layout>
</target>
Creates a file like:
2021-08-25_18-41-31.json
...would possibly mean that Splunk and NLog would possibly fight over file locks.
What's the optimal performance way of logging files for the Splunk Forwarder? :-)

NLog - filters working with final/blackhole

I'd like to setup a way to easily include/exclude certain log messages from an all encompassing log file. Throughout my code I've logged messages based on a "Context" property, which I was then going to use in when conditions to include/exclude the message.
Here is my setup:
<logger writeTo=""
final="true">
<filters>
<when condition="equals('${event-properties:item=Context}', 'Database')"
action="Log"/>
</filters>
</logger>
<logger name="*"
minlevel="Trace"
writeTo="default"/>
My hope was that I could include/exclude any messages with Context='Database' in the first logger and then change the writeTo attribute to either include the message (i.e. writeTo="default") or exclude (i.e. writeTo="").
The issue seems to be that the first logger is including ALL messages and since final is set to true, no messages are allowed to follow through to the catch all logger? Only logs matching the condition in the logger one are written as expected, however ALL logs are being "finalized" by it.
Any ideas a to what is wrong with my configuration?
Maybe try this instead (Remove final="true" and instead use action="LogFinal")
<targets>
<target xsi:type="Null" name="BlackHole" />
</targets>
<rules>
<logger writeTo="BlackHole">
<filters>
<when condition="equals('${event-properties:item=Context}', 'Database')"
action="LogFinal"/>
</filters>
</logger>
</rules>
Looks like you have to specify an actual target to make the custom logger-filters work (Not dependent on LogLevel).

Logging into multiple tables using NLog

I am in search of method or ways to log data into multiple tables using NLog. I have more than one log tables with different structures in my case. And, I would like to log two different datas in these two tables.
Please let me know if there is a way to configure NLog to handle two different tables while logging.
You need two database targets, one for each table.
e.g.
<targets>
<target name="table1" xsi:type="Database"
... />
<target name="table2" xsi:type="Database"
... />
</targets>
<rules>
<logger name="logger1" minlevel="Info" writeTo="table1" />
<logger name="logger2" minlevel="Info" writeTo="table2" />
</rules>

Filtering targets in NLog

I have a logger that configured to multiple targets. Can I filter targets with some conditions?
<logger name="actionsLogger" minlevel="Info" writeTo="fileTarget,rmqTarget1,rmqTarget2" />
I need to always write actions to fileTarget and in some cases to rmqTarget1 and rmqTarget2. Maybe solution is to create multiple loggers with their own targets. But I can't change source code of the project and recompile.
Thanks for the reply. I have found the solution. FilteringWrapper - https://github.com/NLog/NLog/wiki/FilteringWrapper-target. It applies filter for target instead of filter for logger.
<target
xsi:type="FilteringWrapper"
condition="'${event-context:item=Status}'=='Success'"
name="rabbitMQFilteringTarget">
<target
xsi:type="RabbitMQ"
name="rabbitMQTarget"
...
</target>
</target>
Take a look at Conditions on the NLog wiki.
Conditions are filter expressions used with the when filter. They consist of one or more tests. They are used in the when filter to determine if an action will be taken.
You can do this with conditions:
<logger name="actionsLogger" minlevel="Info" writeTo="fileTarget" />
<logger name="actionsLogger" minlevel="Info" writeTo="rabbitMQTarget">
<filters defaultAction="Log">
<when condition="'${event-property:item=Status}'=='Success'" action="Ignore" />
</filters>
</logger>

log4net creates 2 log files instead of expected one, when log4net is configure both in mine and 3rd party dll

I have 2 projects in my solution, both of class library type.
Actions: Project which contains actions, written using White (UI automation framework over MS UI Automation)
Tests: Project with test fixtures and test methods, using MbUnit
I decided to add logging using log4net for both projects. The log4net configuration I'm using is below:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString"
value="c:/AutomationLog/Automation_%date{dd.MM.yy_HH.mm.ss}.log" />
<appendToFile value="false" />
<rollingStyle value="Once" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="10MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date{HH:mm:ss,fff} %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingLogFileAppender" />
</root>
<logger name="root">
<level value="OFF" />
</logger>
</log4net>
I would like that one file is created each run (one per fixture suite run). But two files are created:
Automation_27.01.13_07.33.53.log
Automation_27.01.13_07.33.53.log.1
After investigation I found that log is spitted into 2nd file each time in the same place -- when actions contain types from White is called. Looks like it happens due to White also uses log4net internally.
So, I guess, situation is like this:
I have a class which initializes log4net
I start the fixtures suite
In the tests project there is a class which runs 1st, which contains Log.Info("...")
log file is created
text is appended until..
1st action which references White's types is run from tests project
At this stage a new file is created
I guess it happens because of inside White Dlls there is another call to initialize log4net, it is hard coded inside
Any idea how to prevent log splitting without modifying the code of White (3rd party dlls)?
I have solved the problem by just renaming the config file, white looks for log4net.config name. But I still haven't got the answer - is it possible how to force log4net to be initialized just once, and skip future attempts.

Resources