Use Application Insights logging adapters with NLog C# Console application


I was trying to create a demo console application using C# to check how can I use NLog to send logging information to Microsoft Application insights.

As usual, I have started with the GitHub repo https://github.com/Microsoft/ApplicationInsights-dotnet-logging and started following the steps, but I have seen that the default steps have stopped my logging completely. Even the Console and File listeners are not working! Later I found the solution and thought to share.

Step 1: Create a Console application in Visual Studio

Create a new project in Visual Studio
I have selected Console App (.NET Framework) for my project type
I have named my project as ConsoleNLogAppInsightDemo
Solution opened with default template

Step 2: Add NLog package from Nuget. You can follow the steps here https://github.com/nlog/nlog/wiki/Tutorial as well.

Add Nlog Package

Step 3: Add NLog.Config package as well, unless you want to add it manually.

NLog.Config package in NuGet

Step 4: I have used following basic configuration to log to Console and File.

<?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"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
  <targets>
    <target name="logfile" xsi:type="File" fileName="nlogfile.txt" />
    <target name="logconsole" xsi:type="Console" />
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="logconsole" />
    <logger name="*" minlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

Step 5: Add basic codes in you Program.cs file to test NLog

using System;

namespace ConsoleNLogAppInsightDemo
{
    class Program
    {
        private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
        static void Main(string[] args)
        {
            try
            {
                Logger.Info("Hello world");
                System.Console.ReadKey();
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Hmm! Something is not right.");
            }
        }
    }
}

Step 6: Run your application and see the output in Console and File.

Program output
Log output in local File

Step 7: Now the time is to add Application Insight. Open your Azure subscription, go to the ‘Application Insights’ resource that you have created and copy the ‘Instrumentation Key’.

Here are some screenshots I took while creating the Application Insight resource from scratch.

Search for Application Insights resource in Azure Portal
Click ‘Add’ to create a new resource
Create the resource

Open the resource once the resource creation is successful.

Deployment successful
Copy the instrumentation key

Step 8: Now, go back to your Console application and add the package named ‘Microsoft.ApplicationInsights.NLogTarget’. https://www.nuget.org/packages/Microsoft.ApplicationInsights.NLogTarget/

NLogTarget package from Microsoft

Step 9: Now, open your NLog.config file and add the ‘Extension’, ‘Target’ and ‘Rule’ related to Application Insights as mentioned in this GitHub repo https://github.com/Microsoft/ApplicationInsights-dotnet-logging.

<?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"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
  <extensions>
    <add assembly="Microsoft.ApplicationInsights.NLogTarget" />
  </extensions>
  <targets>
    <target name="logfile" xsi:type="File" fileName="nlogfile.txt" />
    <target name="logconsole" xsi:type="Console" />
    <target name="aiTarget" xsi:type="ApplicationInsightsTarget" >
      <instrumentationKey>YOUR_INSTRUMENTAION_KEY</instrumentationKey>
      <!-- Only required if not using ApplicationInsights.config -->
      <contextproperty name="threadid" layout="${threadid}" />
      <!-- Can be repeated with more context -->
    </target>
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="logconsole" />
    <logger name="*" minlevel="Debug" writeTo="logfile" />
    <logger name="*" minlevel="Trace" writeTo="aiTarget" />
  </rules>
</nlog>

Step 10: Now, add tracing code in your Program.cs file and run it.

Logger.Trace("This should go to App insight");

Here is my full code:

using System;

namespace ConsoleNLogAppInsightDemo
{
    class Program
    {
        private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
        static void Main(string[] args)
        {
            try
            {
                Logger.Info("Hello world");
                Logger.Trace("This should go to App insight");
                System.Console.ReadKey();
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Hmm! Something is not right.");
            }
        }
    }
Completely blank output

Check the output window in Visual Studio after running the application. You would see a message saying that ‘Application Insights Telemetry (unconfigured)’.

Application Insights Telemetry (unconfigured)

At this point I was completely clueless why it would say unconfigured. After banging my head to the laptop screen few times, I have figured out the problem.

It seems, when you add the ‘Microsoft.ApplicationInsights.NLogTarget’ package from Nuget, it automatically adds some code in your App.config file.

App.config file content before adding Microsoft.ApplicationInsights.NLogTarget
App.config file content after adding Microsoft.ApplicationInsights.NLogTarget
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
    </configSections>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <nlog>
        <extensions>
            <add assembly="Microsoft.ApplicationInsights.NLogTarget" />
        </extensions>
        <targets>
            <target type="ApplicationInsightsTarget" name="aiTarget" />
        </targets>
        <rules>
            <logger name="*" minlevel="Trace" writeTo="aiTarget" />
        </rules>
    </nlog>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

So, it also adds the NLog configuration in App.config file, which is clearly not configured with the instrumentation key.

At this point, you need to either put the instrumentation key in App.config and use the NLog configuration from there (plus remove the NLog.config file) or remove the NLog configuration from App.config completely so that the NLog.config file can be taken into consideration. I would suggest the latter since your NLog.config file can have some existing configurations already, with additional targets and rules.

So I have decided to remove <nlog> block from my App.config and everything started to work as expected.

Console output came back
Application Insights Telemetry (unconfigured) message is now gone

You will see that the Application Insights Telemetry (unconfigured) message is now gone from output. Also, the data will show up in Application Insights search window.

Application insights search window showing data

So, you can say it was my stupidity that has caused this issue in the first place, but I thought to share the good news with you any way 😀