Application Insights setup for dotnet core 2.1

Application Insights is often used for logging, but did you really read the name? The goal of Application Insights is getting a good insight view of how your application is working.

The best way to get a quick overview of what’s going on with your application is get a nice Application Map. In this tutorial I’ll show you how you can configure Application Insights for dotnet core 2.1, get a nice overview in the Application Map and query your data.

Add Application Insights to dotnet core

Add NuGet references

You’ll need to add 2 NuGet packages to your project:

<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.7.1" />
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.10.0" />

Configure logging

Change the CreateWebHostBuilder in your Program.cs so Application Insights is configured via the settings of your appsettings.json file

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    var webHostBuilder = WebHost.CreateDefaultBuilder(args);
    webHostBuilder.UseStartup<Startup>()
        .ConfigureLogging((hostingContext, logging) =>{
        var configSectionForLogging = hostingContext.Configuration.GetSection("Logging");
            if (!string.IsNullOrWhiteSpace(configSectionForLogging["ApplicationInsights:InstrumentationKey"]))
            {
                logging.AddApplicationInsights(configSectionForLogging["ApplicationInsights:InstrumentationKey"]?.ToString() ?? "");
                logging.AddFilter<ApplicationInsightsLoggerProvider>("", Enum.Parse<LogLevel>(configSectionForLogging["LogLevel:Default"] ?? "Information"));
                logging.AddFilter<ApplicationInsightsLoggerProvider>("Microsoft", Enum.Parse<LogLevel>(configSectionForLogging["LogLevel:Microsoft"] ?? "Warning"));
            }
    });
    return webHostBuilder;
}

You can set a different filter for your logs and the microsoft logs. Here in my example, if no loglevel is found, the application logs will default to “Information” and the Microsoft logging will default to “Warning” and above.

Appsettings

In my appsettings.json I added 2 sections in the main logging section

"Logging": {
    "ApplicationInsights": {
        "InstrumentationKey": "<your AppInsights key>",
        "RoleName": "CoreDemo_API"
    },
    "LogLevel": {
        "Default": "Information",
        "Microsoft": "Warning"
    }
}

The “ApplicationInsights” section contains the InstrumentationKey and a friendly “RoleName”. This name will show up in the Application Map (overview) of Application Insights. By default the resource name of your application is used. To make the global view more readable, we’ll set the rolename. Another advantage of using the RoleName is that you can use it in your queries.

The second section is “LogLevel”. The “Default” is the loglevel for our application. The “Microsoft” is the loglevel filter for Microsoft loggings.

TelemetryInitializer

Next, we tell our application to use the RoleName when logging to AppInsights. This is how our Application Map gets more useful names. To inject the Rolename with our logs, we’ll need to create a class that inherits from ITelemetryInitializer

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;

namespace DevProtocol.CoreDemo.Api.Infrastructure
{
    public class LoggingInitializer : ITelemetryInitializer
    {
        readonly string roleName;
        public LoggingInitializer(string roleName = null)
        {
            this.roleName = roleName ?? "api";
        }
        public void Initialize(ITelemetry telemetry)
        {
            telemetry.Context.Cloud.RoleName = roleName;
        }
    }
}

Now in our Startup.cs we add the class as singleton and inject the RoleName

services.AddSingleton<ITelemetryInitializer>(new LoggingInitializer(Configuration["Logging:ApplicationInsights:RoleName"]));

So your ConfigureServices should now look like:

 public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ITelemetryInitializer>(new LoggingInitializer(Configuration["Logging:ApplicationInsights:RoleName"]));
    services.AddApplicationInsightsTelemetry(options => {
        options.EnableDebugLogger = false;
    });
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Avoid double logging statements

Microsoft is adding an Application Insights logger when you start debugging with Visual Studio. To avoid double logging statements you need to disable the AppInsightsDebugLogger. After you added the ITelemetryInitializer in your Startup.cs you can add the following statement to avoid the doubles in your logging:

services.AddApplicationInsightsTelemetry(options => {
    options.EnableDebugLogger = false;
});

Logging statements

From C# 6 we’re spoiled with the string interpolation feature. As great as it is you’ll need to stop using it for your logging statements. The problem with string interpolation is that it makes each customDimension unique.

If you check the overloads you’ll notice that the logging methods have an overload that accepts an argument list:

logging overload for args

So don’t use:

var id = 42;
_logger.LogWarning($"Warning logging about {id}");

you should use

var id = 42;
_logger.LogWarning("Warning logging about {id}", id);

This allows you to search all “Warning logging about {id}” statements, count the statements,…

log data

Query your data

Via log analytics you can query your data with KQL (Keyword Query Language).

To get our data we can use:

traces 
| where cloud_RoleName == "CoreDemo_API"
| where severityLevel == 2
| where customDimensions.["{OriginalFormat}"] == "Warning logging about {id}"
| where timestamp > ago(1d)
  • cloud_RoleName: the RoleName we configured via the ITelemetryInitializer
  • severityLevel: (0=Tracing, 1=Information, 2=Warning, 3=Error)
  • customDimensions: search for a particular logging statement. Here it’s useful you didn’t use string interpolation in your log statement
  • timestamp: here we request the data of the last 24 hours

References