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:
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,…
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
- https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview
- https://docs.microsoft.com/bs-latn-ba/azure/azure-monitor/app/ilogger
- https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-map
- https://docs.microsoft.com/en-us/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference