Enabling Application Insights in Sitecore Commerce 9.0.1

January 14, 2021

Getting logging and dependency tracking information to Application Insights from Sitecore Commerce version 9.0.1 takes a bit of configuration and code. It's worth it though especially since Sitecore 9 has introduced a number of new micro-services. I highly recommend you read Alex Smagin's post below on getting better observability of Sitecore with Azure Application Map. This map allows you to view your entire app infrastructure and drill into problem services or dependencies.

https://asmagin.com/2019/07/05/getting-better-observability-of-sitecore-with-azure-application-insights-map/

Configuration

Application Insights configuration becomes better in future versions of Sitecore. For 9.0.1 you can extend config.json with some additional parameters that come in 9.0.2. In the JSON below, we're adding TelemetryEnabled to the ApplicationInsights section and ApplicationInsightsLoggingEnabled and SerilogLoggingEnabled to the Logging section. With the config.json settings below you would be sending Error level logging and telemetry data to ApplicationInsights and disabling local Serilog logs.

...
"ApplicationInsights": {
  "InstrumentationKey": "USE YOUR APPLICATION INSIGHTS ID",
  "MinimumLevel": "Error",
  "TelemetryEnabled": true
},
"Logging": {
  "LogLevel": {
    "Default": "Error",
    "System": "Error",
    "Microsoft": "Error"
  },
  "ApplicationInsightsLoggingEnabled": true,
  "SerilogLoggingEnabled": false
}
...
        

Code

In addition to the configuration above, you need to write code to take advantage of these new parameters. We'll add a couple classes that will help us identify which resource is logging data. Then we'll hook into the application startup and adjust how Application Insights is initialized. These changes should be made in your Sitecore Commerce Engine project.

AppSettings.cs

First, we'll create a class that will allow us to inject the resource's EnvironmentName into the TelemetryInitializer. This POCO class just identifies the data we want passed from the AppSettings section of config.json.

namespace Sitecore.Commerce.Engine
{
    public class AppSettings
    {
        public string EnvironmentName { get; set; }
    }
}
        

CloudRoleNameInitializer.cs

Next, we'll create a class that tells Application Insights what role name to use for this data

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Extensions.Options;

namespace Sitecore.Commerce.Engine
{
    public class CloudRoleNameInitializer : ITelemetryInitializer
    {
        private IOptions<AppSettings> _config;

        public CloudRoleNameInitializer(IOptions<AppSettings> configuration)
        {
            _config = configuration;
        }

        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry?.Context?.Cloud != null)
            {
                string name = _config?.Value?.EnvironmentName;

                if (!string.IsNullOrWhiteSpace(name))
                    telemetry.Context.Cloud.RoleName = name;
            }
        }
    }
}
        

Startup.cs

There should already be a Startup.cs class in your project that you will now extend to take advantage of the new configuration parameters and classes. This class can be long to begin with so I will only capture the main hightlights below:

...
public class Startup
{
    private readonly TelemetryClient _telemetryClient;
...
    public Startup(
...
    {
...
        if (!long.TryParse(Configuration.GetSection("Serilog:FileSizeLimitBytes").Value, out var fileSize))
        var appInsightsInstrumentationKey = configuration.GetSection("ApplicationInsights:InstrumentationKey").Value;
        _telemetryClient = !string.IsNullOrWhiteSpace(appInstightsInstrumentationKey) ? new TelemetryClient { InstrumentationKey = appInsightsInstrumentationKey } : new TelemetryClient();
        if (bool.TryParse(configuration.GetSection("Logging:SerilogLoggingEnabled")?.Value, out var serilogEnabled) && serilogEnabled)
        {
            if (!long.TryParse(configuration.GetSection("Serilog:FileSizeLimitBytes").Value, out var fileSize))
...
        }
...
    }
...
    public void ConfigureServices(IServiceCollection services)
    {
...
        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
        services.Configure<ITelemetryInitializer, CloudRoleNameInitializer>();
        services.AddSingleton(_telemetryClient);
        TelemetryConfiguration.Active.DisableTelemetry = true;
        services.Add(new ServiceDescriptor(typeof(TelemetryClient), typeof(TelemetryClient), ServiceLifetime.Singleton));
...
    }
...
    public void Configure(
...
    {
...
        var appInsightsSettings = applicationInsightsSettings.Value;
        if (!bool.TryParse(Configuration.GetSection("ApplicationInsights:TelemetryEnabled")?.Value, out var telemetryEnabled) || !telemetryEnabled))
        {
            TelemetryConfiguration.Active.DisableTelemetry = true;
        }

        if (loggingSettings.Value != null && loggingSettings.Value.ApplicationInsightsLoggingEnabled)
        {
            var appInsightsSettings = applicationInsightsSettings.Value;
            appInsightsSettings.DeveloperMode = _hostEnv.IsDevelopment();
...
        }
...
    }
}