NLog allows me to use SplitGroup
to log my messages to several targets. I'd like to use this feature to log each message to a common, user-specific and date-specific logs at once:
<variable name="commonLog" value="${logDir}\Common.log" />
<variable name="username" value="${identity:fSNormalize=true:authType=false:isAuthenticated=false}" />
<variable name="userLog" value="${logDir}\ByUser\${username}.log" />
<variable name="dateLog" value="${logDir}\ByDate\${shortdate}.log" />
<target name="logFiles" xsi:type="SplitGroup">
<target xsi:type="File" fileName="${commonLog}" layout="${myLayout}" />
<target xsi:type="File" fileName="${userLog}" layout="${myLayout}" />
<target xsi:type="File" fileName="${dateLog}" layout="${myLayout}" />
</target>
This is great, but I also want to use different layouts for different levels of severity. For example, errorLayout
would include exception information and insert [!]
marker so I could later highlight errors in log viewers like BareTail:
<variable name="stamp" value="${date} ${username} ${logger}" />
<variable name="debugLayout" value="${stamp} ... ${message}" />
<variable name="infoLayout" value="${stamp} [i] ${message}" />
<variable name="warnLayout" value="${stamp} [!] ${message}" />
<variable name="errorLayout"
value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" />
<!-- logFiles target -->
<rules>
<logger name="*" level="Debug" writeTo="logFiles" layout="debugLayout" />
<logger name="*" level="Info" writeTo="logFiles" layout="infoLayout" />
<logger name="*" level="Warn" writeTo="logFiles" layout="warnLayout" />
<logger name="*" level="Error" writeTo="logFiles" layout="errorLayout" />
</rules>
This code assumes Error
s always come with exceptions and Warning
s don't but that's not the point.
The problem is this configuration is wrong. It won't work because logger
does not have layout
attribute. It's defined for target
only.
Layout which is being used must be declared by targets themselves but I see no means of specifying different layouts for different severity levels.
For now, I had to copy-paste the same configuration code four times just to have four different layout
s for same set of files:
<targets>
<target name="logFilesDebug" xsi:type="SplitGroup">
<target xsi:type="File" fileName="${commonLog}" layout="${debugLayout}" />
<target xsi:type="File" fileName="${userLog}" layout="${debugLayout}" />
<target xsi:type="File" fileName="${dateLog}" layout="${debugLayout}" />
</target>
<target name="logFilesInfo" xsi:type="SplitGroup">
<target xsi:type="File" fileName="${commonLog}" layout="${infoLayout}" />
<target xsi:type="File" fileName="${userLog}" layout="${infoLayout}" />
<target xsi:type="File" fileName="${dateLog}" layout="${infoLayout}" />
</target>
<target name="logFilesWarn" xsi:type="SplitGroup">
<target xsi:type="File" fileName="${commonLog}" layout="${warnLayout}" />
<target xsi:type="File" fileName="${userLog}" layout="${warnLayout}" />
<target xsi:type="File" fileName="${dateLog}" layout="${warnLayout}" />
</target>
<target name="logFilesError" xsi:type="SplitGroup">
<target xsi:type="File" fileName="${commonLog}" layout="${errorLayout}" />
<target xsi:type="File" fileName="${userLog}" layout="${errorLayout}" />
<target xsi:type="File" fileName="${dateLog}" layout="${errorLayout}" />
</target>
</targets>
<rules>
<logger name="*" level="Debug" writeTo="logFilesDebug" />
<logger name="*" level="Info" writeTo="logFilesInfo" />
<logger name="*" level="Warn" writeTo="logFilesWarn" />
<logger name="*" level="Error" writeTo="logFilesError" />
</rules>
This just hurts my eyes.
Is there any better way to do this and avoid duplication?
An alternate solution is to use the when condition in the layout.
target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}"
I wanted to just provide the exception message when anything less than error. When there was an error I wanted full stack trace.