NLog - Only log while debugging - nlog

Take this simple NLog example configuration:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logfile" />
</rules>
</nlog>
How can this be set up to only log while debugging, and not when run in production?
EDIT:
To make things a bit more challenging: My NLog configuration files are centralized, shared over all applications/services/sites. So I would like to avoid altering every single project and just modify the config files.

A simple solution would be to have a NLog.config file (whose contents will be overriden - you'll see later), plus one NLog config file per solution configuration/environment (let's say, NLog.debug.config and NLog.release.config). For example:
Then you configure a Pre-build event command line to copy the config file corresponding to the current active configuration:
The complete command you should paste there:
del "$(ProjectDir)NLog.config"
if "$(ConfigurationName)"=="Debug" (
copy "$(ProjectDir)NLog.debug.config" "$(ProjectDir)NLog.config"
) else (
copy "$(ProjectDir)NLog.release.config" "$(ProjectDir)NLog.config"
)
This will copy NLog.debug.config to NLog.config (effectively overriding it) if DEBUG is the current active configuration/environment, otherwise it will copy NLog.release.config.
A shorter version would look like this (note the file naming diference though):
del "$(ProjectDir)NLog.config"
copy "$(ProjectDir)NLog.$(ConfigurationName).config" "$(ProjectDir)NLog.config"
Another thing to note is that during compilation the compiler will throw various warnings about duplicate declarations related to NLog. The reason is that the compiler will find 2 (or more) distinct configuration files for NLog and their declarations will collide. In order to fix that you have to change the Properties of each of your extra NLog configuration files to make the build action not copy them. For example:
Do not repeat yourself
Lastly, you may not want to duplicate common/shared targets|rules|whatnot to avoid having to change them in multiple files. To achieve that, you can move these common/shared parts to another file and use <include />.

I see three solutions here.
1) Using config file and its transformations. For the moment the transformations are supported for web applications (Im talking about VS2012). For desktop app you need to install additional extension.
2) Use two targets, one for development (I assume debugging=development in your case) and the second for production. At runtime you need to leave actual one by removing the other.
UPDATE
3) If you don't want to alter the projects it is possible to apply custom conditions to the logger depending on custom Layout Renderer (see example of how to make a custom layout renderer). In your case the layout renderer should return current Build Configuration (Debug or Release) of executing assembly. As a result the condition will look like this:
<rules>
<logger name="*" writeTo="logfile">
<filters>
<when condition="equals('${buildConfiguration}','Release')" action="Ignore" />
</filters>
</logger>
</rules>
where ${buildConfiguration} is your custom layout renderer.
PS And dont forget to put this
<extensions>
<add assembly="NameOfMyAssemblyThatContainsMyLayoutRenderer" />
</extensions>
to the nlog.config so NLog knows about the layout renderer.

I have based my answer on #neleus answer above but it still took me hours to get something working. Here is the completed guide incl. how to set up the LayoutRenderer. For the NLog.config you need:
<extensions>
<add assembly="AssemblyName" />
</extensions>
<target xsi:type="AsyncWrapper" name="asyncProd">
<target xsi:type="File" name="logfileProc" fileName="${basedir}/logs/${buildConfiguration}.log"/>
</target>
<logger name="*" minlevel="Info" writeTo="asyncProd">
<filters>
<when condition="equals('${buildConfiguration}','Debug')" action="Ignore" />
</filters>
</logger>
The target above is only for newbees to NLog so they have something running more quickly. Using the custom LayoutRenderer in the filename helps with debugging as you can see it's output in the file that is produced.
Then create a class called BuildConfigLayoutRenderer which I adapted from neleus' link
[LayoutRenderer("buildConfiguration")]
[ThreadAgnostic]
public class BuildConfigLayoutRenderer : LayoutRenderer {
private String buildconfig;
private String GetBuildConfig() {
if (buildconfig != null) {
return buildconfig;
}
#if DEBUG
buildconfig = "Debug";
#else
buildconfig = "Release";
#endif
return buildconfig;
}
protected override void Append(StringBuilder builder, LogEventInfo logEvent) {
builder.Append(GetBuildConfig());
}
}
Important is the string passed into the LayoutRendererAttribute. They need to match with what you register (needs to happen as early as possible in your code; main()) and the NLog.config.
LayoutRenderer.Register<BuildConfigLayoutRenderer>("buildConfiguration");
Now ${buildConfiguration} will work.
You can also use this for even more build configurations but you need to remember to add the filter that ignores that rule. I also tried the opposite, meaning to have action="Log" in the rule to reduce the number of filters needed. Later I realised that is non-sense because the default is to use the logger... so you have to ignore it.

This answer nLog forum worked for us.
Reprinted below incase it ever gets lost.
What you can do is have two NLog.config files:
NLog.config
and NLog.Debug.config
In your code, somewhere close to the main method you can do:
#if DEBUG
LogManager.Configuration = new
XmlLoggingConfiguration("NLog.Debug.config");
#endif
Now if most of the configuration is the same you can perhaps use
include files - put everything htat is common (targets, etc.) into
NLog.common.config and reference it with
NLog.debug.config:
<include file="NLog.common.config" />
<logger name="*" minLevel="Trace" writeTo="debug" />
<logger name="*" minLevel="Info" writeTo="viewer" final="true" />
NLog.release.config:
<include file="NLog.common.config" />
<!-- Release rules -->
<logger name="*" minlevel="Info" writeTo="file" />
<logger name="*" minLevel="Error" writeTo="event" />
Let me know if it helps.
Jarek

If a little code is allowed at runtime then one can do this:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variable name="myLogLevel" value="Off" />
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="${var:myLogLevel}" writeTo="logfile" />
</rules>
</nlog>
And then at startup do this:
#if DEBUG
if (IsDebugMode)
{
LogManager.Configuration.Variables["myLogLevel"] = "Debug";
LogManager.ReconfigExistingLoggers();
}
#endif
See also: https://github.com/nlog/NLog/wiki/Filtering-log-messages#semi-dynamic-routing-rules

Related

Log in a file only if the database fails?

I have a scenario where I want to log in a file only if the database fails for some reason.
Is it possible to achieve that using NLog ?
Yes, you could use the FallbackGroup target for that. In the fallback group you should configure the database and file target.
e.g.
<target xsi:type="FallbackGroup" name="all" returnToFirstOnSuccess="true">
<target name="target1" xsi:type="Database" ... />
<target name="target2" xsi:type="File" ... />
</target>
<rules>
<logger name="*" minlevel="Trace" writeTo="all" />
</rules>
See https://github.com/NLog/NLog/wiki/FallbackGroup-target

NLog logs Error twice in same file

I am trying to figure out why NLog logs my error twice.
here is my config file:
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="debug" xsi:type="File" FileName="DebugTestFile.log" layout="${message} ${exception:format=tostring}" />
</targets>
<rules>
<logger name="*" level="Debug" writeTo="debug" />
</rules>
</nlog>
Now when I call NLog.Debug(myException); the output is my exception gets printed twice.
If I call NLog.Debug(myException, "My Test Message String"); then the error gets printed out once along with my test message.
What exactly am I doing wrong? According to https://github.com/NLog/NLog/wiki/How-to-Log-Exceptions my configuration is correct.
I tried changing my layout to the following: layout="${message} and when I ran NLog.Debug(myException); it only printed the error once.
However now when I ran NLog.Debug(myException, "My Test Message String"); it only printed my message without the error that comes from exception.
Could this be a bug with NLog?
Updated Answer
NLog.Web.AspNetCore v4.8.6 changes registration of NLog Logging Provider, so one is now allowed to call both AddNLog and UseNLog without experiencing double logging.
NLog 5.0 implements validation of incorrect duplicate target configuration, so one will not experience double logging when using incorrect NLog configuration.
Original Answer
If you are using NLog in AspNetCore, then the problem can be caused by calling UseNLog together with AddNLog or ConfigureNLog.
You should only use UseNLog together with NLog.Web.LogBuilder.ConfigureNLog (Stop using AddNLog):
https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-2#4-update-programcs
This is seems to be because of rule in config file, just change writeTo for each logger, in my case I was able to reolve this issue by following same steps:
Example:
Earlier config file which was having issue:
<rules>
<logger name="*" minlevel="Info" writeTo="console" />
<logger name="*" minlevel="Error" writeTo="console" />
</rules>
Corrected config file:
<rules>
<logger name="*" minlevel="Info" writeTo="console" />
<logger name="*" minlevel="Error" writeTo="console1" />
</rules>

NLog 4.0 ignores final attribute on a rule

My application is using NLog configured with NLog.config shown below. It also uses RavenDB database which by default uses active NLog settings for logging.
It produces a lot of DEBUG and INFO messages that pollute the log. I do want to log ERROR and WARN messages. All of the records created by RavenDB come from namespaces that start with Raven.
I created the rules as shown below. Basically there is a final rule that prevents INFO/DEBUG messages that come from Raven.* namespace to get written into the log file. Everything was working well until I upgraded the NuGet packages to NLog 4.0. Now all the RavenDB messages are written into the log file.
Is this a bug or there is some configuration change happened across the NLog versions?
<?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>
<target name="file" xsi:type="AsyncWrapper" queueLimit="1000" overflowAction="Discard">
<target
name="file"
xsi:type="File"
layout="${longdate} - ${level:upperCase=true} - ${identity} - ${logger} - ${message}${onexception:inner=${newline}${exception:format=tostring}${newline}}"
fileName="D:/Logs/AppName/${shortdate}.log" />
</target>
</targets>
<rules>
<logger name="Raven.*" writeTo="file" minlevel="Warn" final="true" />
<logger name="*" writeTo="file" minlevel="Debug" />
</rules>
</nlog>
Apparently there was a logic change in NLog 4. It does not mark messages from Raven namespace with level below the Warn final any longer.
http://nlog-project.org/2015/06/09/nlog-4-has-been-released.html
So the rule would have to change to send messages in the Raven.* namespace with maxlevel="INFO" into a null target.

Is it possible to have more Loggers in ServiceStack for the same AppHost?

I'm creating a Plugin for ServiceStack that contains certain services. However, I want these services to Log to another DB (in my case) that the other services in the AppHost.
Is it possible to register 2 ILog interfaces inside the AppHost?
The ServiceStack.Logging.LogManager.GetLogger(GetType()) will always return an ILog interface. Do I need to create a second ILog implementation for the other Logger?
I'm using NLog.
I'm not familiar with ServiceStack, so my suggestion might not make sense (but it does make sense when considering NLog in isolation).
Can't you just configure another Target in the NLog.config file and configure your loggers to write to that Target?
For example...
Configure some targets in the NLog.config (I am configuring a console target and a file target)
<targets>
<target name="file" xsi:type="File" layout="${longdate} | ${level} | ${logger} | ${message}" fileName="${basedir}/${shortdate}.log" />
<target name="console" xsi:type="ColoredConsole" layout="${longdate} | ${level} | ${logger} | ${message}" />
</targets>
Configure some rules
<rules>
<logger name="Your.Name.Space1.*" minlevel="Trace" writeTo="file" />
<logger name="Your.Name.Space2.*" minlevel="Trace" writeTo="file" />
<logger name="*" minLevel="Trace" writeTo="console" />
</rules>
Now, all classes from Your.Name.Space1 and Your.Name.Space2 will log to the "file" target while all other classes will log to the "console" target. You could add "final=true" to the loggers for your classes if you want their logs to appear only in the "file" target.
I think that should all you to do what you want to do.

NLOG creating debug.txt file when minlevel = "Info"

I am not very familiar with NLOG, so I am hoping someone can point me in the right direction to solving this problem. I don't want NLOG to create a debug.txt file. I thought simple updating the minlevel to "Info", would solve it, but it does not.
Here are the settings in my app.config file that point NLOG:
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true">
<variable name="applicationName" value="TheNameOfMyApplication" />
<include file="\\<PathToNlogConfig>\NLog.config" />
</nlog>
And in my NLog.config file in the rules section:
<logger name="Name.Space.Apps.*" minlevel="Info" writeTo="consoleapps" final="true" />
<logger name="*" minlevel="Info" writeTo="fileOut" />
What else do I need to configure to stop this debug.txt file from being created?
Thanks
Solved it. Turns out we were using a library to log to NLOG, and NLOG was grabbing the namespace from that library, and hence hitting a different rule.

Resources