<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Arjan/Blog</title><link href="http://world.optimizely.com" /><updated>2023-08-18T02:54:17.0000000Z</updated><id>https://world.optimizely.com/blogs/arjanblog/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Finetuning Azure Application Insights in CMS12</title><link href="https://world.optimizely.com/blogs/arjanblog/dates/2023/7/finetuning-application-insights-in-cms12/" /><id>&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have ever managed a DXP environment, you might have found the Azure Application Insights log to look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/700792bbeae34e909ff55e2af2139221.aspx&quot; width=&quot;1094&quot; height=&quot;274&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The Dependency logging is dominant, representing most of the data. Also note the warning that sampling is active: not every message comes through.&lt;br /&gt;On closer inspection, the Dependency logging mostly consists of uninformative SQL messages:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/f1e9203a9b744c309d783ab5c5b7ed5d.aspx&quot; width=&quot;409&quot; height=&quot;398&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The main goal to achieve was:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create high fidelity application logging for our custom codebase&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This was hindered by the &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/azure-monitor/app/sampling&quot;&gt;telemetry sampling&lt;/a&gt;&amp;nbsp;as not every message was guaranteed to come through.&lt;br /&gt;To reach this goal, the following subtasks are implemented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure custom application logging to allow Informational messages&lt;/li&gt;
&lt;li&gt;Reduce Dependency logging to the level where sampling can be turned off&lt;/li&gt;
&lt;li&gt;Retain SQL logging for longer-duration queries&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Application Insights provider setting&lt;/h2&gt;
&lt;p&gt;Configure the provider for ApplicationInsights in appsettings.json. See &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0#configure-logging&quot;&gt;documentation&lt;/a&gt;.&lt;img src=&quot;data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7&quot; /&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Warning&quot;,
      &quot;Microsoft&quot;: &quot;Warning&quot;,
      &quot;EPiServer&quot;: &quot;Warning&quot;,
      &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Warning&quot;
    },
    &quot;ApplicationInsights&quot;: {
      &quot;LogLevel&quot;: {
        &quot;Default&quot;: &quot;Warning&quot;,
        &quot;MyNamespace&quot;: &quot;Information&quot;,
        &quot;Microsoft&quot;: &quot;Warning&quot;,
        &quot;EPiServer&quot;: &quot;Warning&quot;
      }
    }
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will cause everything to emit Warnings only, except for our projects&#39; messages which are &lt;strong&gt;Information&lt;/strong&gt; and up.&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Custom Application Insights options&lt;/h2&gt;
&lt;p&gt;To make these changes, the following IServiceCollection extension method is introduced:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public static class ServiceConfigurationContextExtensions
{
    public static void AddCustomApplicationInsights(this IServiceCollection services)
	{
        ApplicationInsightsServiceOptions aiOptions = new ApplicationInsightsServiceOptions();

        // Disables adaptive sampling.
        aiOptions.EnableAdaptiveSampling = false;

        // Disables QuickPulse (Live Metrics stream).
        aiOptions.EnableQuickPulseMetricStream = true;
        aiOptions.EnableDependencyTrackingTelemetryModule = true;

        services.AddApplicationInsightsTelemetry(aiOptions);
        services.AddApplicationInsightsTelemetryProcessor&amp;lt;SqlDependencyFilter&amp;gt;();

        services.ConfigureTelemetryModule&amp;lt;DependencyTrackingTelemetryModule&amp;gt;((module, o) =&amp;gt;
        {
            module.EnableSqlCommandTextInstrumentation = true; // Injects SQL cmd text into telemetry
        });
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notably, this will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;turn off adaptive sampling&lt;/li&gt;
&lt;li&gt;add a custom telemetry processor&lt;/li&gt;
&lt;li&gt;turn on SQL command text logging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is loaded in startup.cs, and must be before &lt;strong&gt;AddCmsCloudPlatformSupport&lt;/strong&gt;.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    if (!_webHostingEnvironment.IsDevelopment())
    {
        services.AddCustomApplicationInsights();
        services.AddCmsCloudPlatformSupport(_configuration);
        services.AddCommerceCloudPlatformSupport(_configuration);
    }

    ....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The custom telemetry processor SqlDependencyFilter introduces a filter to all messages &quot;SQL&quot; to only process if the duration is greater than 100ms:&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class SqlDependencyFilter : ITelemetryProcessor
{
    private ITelemetryProcessor Next { get; set; }

    // next will point to the next TelemetryProcessor in the chain.
    public SqlDependencyFilter(ITelemetryProcessor next)
    {
        this.Next = next;
    }

    public void Process(ITelemetry item)
    {
        // To filter out an item, return without calling the next processor.
        if (!OKtoSend(item)) { return; }

        this.Next.Process(item);
    }

    private bool OKtoSend(ITelemetry item)
    {
        var dependency = item as DependencyTelemetry;

        if (dependency == null || dependency.Type != &quot;SQL&quot;) return true; // only filter for Dependency &amp;amp; SQL

        if (dependency.Duration.TotalMilliseconds &amp;lt; 100) return false; // we don&#39;t want shorties

        return true; // this is a long SQL query
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;Typically, Application Insights for a site with these changes applied looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/beea0ba136a0444881d18e176d8fce6a.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With a notably smaller Dependency component. Its SQL logging will be for queries with a minimum of 100ms duration, and the actual SQL command will be included.&lt;br /&gt;Also note the sampling warning message has disappeared.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/57b3137d342948b196bc42ca38c89688.aspx&quot; width=&quot;409&quot; height=&quot;411&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Our application&#39;s Information messages are unfiltered, appearing as Trace messages:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/09989be6c22246a382bea64d6fdca243.aspx&quot; width=&quot;523&quot; height=&quot;215&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Any thoughts or concerns, please let me know!&lt;/p&gt;</id><updated>2023-08-18T02:54:17.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>