Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NLog - Only log while debugging

Tags:

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.

like image 690
Stijn Avatar asked Nov 10 '14 14:11

Stijn


4 Answers

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:

All needed NLog config files

Then you configure a Pre-build event command line to copy the config file corresponding to the current active configuration:

Pre-build event command line

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:

NLog.debug.config Properties

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 />.

like image 106
jweyrich Avatar answered Oct 18 '22 12:10

jweyrich


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.

like image 20
neleus Avatar answered Oct 18 '22 13:10

neleus


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.

like image 32
penCsharpener Avatar answered Oct 18 '22 14:10

penCsharpener


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

like image 31
Kabuo Avatar answered Oct 18 '22 12:10

Kabuo