<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Dave Paquette]]></title>
  <subtitle><![CDATA[Caffeine Driven Development]]></subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="http://www.davepaquette.com/"/>
  <updated>2020-05-27T01:44:32.224Z</updated>
  <id>http://www.davepaquette.com/</id>
  
  <author>
    <name><![CDATA[Dave Paquette]]></name>
    <email><![CDATA[contactme@davepaquette.com]]></email>
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[Scaling Azure Functions from Consumption Plan to Premium Plan (and back again)]]></title>
    <link href="http://www.davepaquette.com/archive/2020/05/23/scaling-azure-functions-from-consumption-plan-to-premium-hosting-plan.aspx"/>
    <id>http://www.davepaquette.com/archive/2020/05/23/scaling-azure-functions-from-consumption-plan-to-premium-hosting-plan.aspx</id>
    <published>2020-05-23T16:30:00.000Z</published>
    <updated>2020-05-27T01:44:32.224Z</updated>
    <content type="html"><![CDATA[<p>Azure Functions, when hosted on a consumption plan, are great for most scenarios. You pay per use which is great for keeping costs down but there are some downsides and limitations. One of those is the time it takes to cold start your function app. If your function app hasn’t been triggered in some time, it can take a while for the a new instance to start up to run your app. Likewise, if a very sudden spike in load occurs, it can take some time for the consumption plan to start up enough instances to handle that load. In the meantime, you might have clients getting timeouts or failed requests.</p>
<p>Azure Functions offers another hosting model called <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan" target="_blank" rel="external">Azure Functions Premium Plan</a>. With premium plans, instead of paying per function execution, you pay for the underlying compute instances that are hosting your functions. This is often more expensive, but it also ensures there are always a pre-set number of warmed instances ready to execute your function.</p>
<p>That’s great, but what if I only really need those pre-warmed instances for a short period of time when I’m expecting a lot of incoming traffic. The rest of the time, I would rather use a Consumption Plan to save on hosting costs.</p>
<p>I thought the choice of hosting plan was something you needed to make up front but it turns out that you can actually move an Azure Function App from a consumption plan to a premium plan (and back again).</p>
<p>Thanks to <a href="https://twitter.com/stimms/" target="_blank" rel="external">Simon Timms</a> for starting this discussion on Twitter. We got very helpful responses from folks on the Azure Functions team:</p>
<p><a href="https://twitter.com/jeffhollan/" target="_blank" rel="external">Jeff Hollan</a> has a great <a href="https://github.com/Azure-Samples/functions-csharp-premium-scaler" target="_blank" rel="external">sample</a> using an Azure Durable Function to scale an Azure Function App to a premium plan for a specified amount of time, then automatically scale back down to a consumption plan.</p>
<p><blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/6C9l3PQDoZ" target="_blank" rel="external">https://t.co/6C9l3PQDoZ</a></p>&mdash; Jeff Hollan (@jeffhollan) <a href="https://twitter.com/jeffhollan/status/1245779682961674240?ref_src=twsrc%5Etfw" target="_blank" rel="external">April 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>This is a super cool sample. It uses the <a href="https://docs.microsoft.com/en-us/rest/api/resources/" target="_blank" rel="external">Azure Resource Manager REST API</a> to make changes to the target function app resources. For my project however, I didn’t really want to spin up another Azure Function to manage my Azure Functions. I just wanted an easy way to scale my 12 function apps up to premium plans for a couple hours, then scale them back down to a consumption plan.</p>
<p>I decided to try using the AZ CLI for this and it turned out really well. I was able to write a simple script to scale up and down.</p>
<h2 id="Setting_up_the_AZ_CLI">Setting up the AZ CLI</h2><p>First up, <a href="https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest" target="_blank" rel="external">install the az cli</a>.</p>
<p>Once installed, you’ll need to login to your Azure Subscription.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az login</span><br></pre></td></tr></table></figure>
<p>A browser window will popup, prompting you to log in to your Azure account. Once you’ve logged in, the browser window will close and the az cli will display a list of subscriptions available in your account. If you have more than one subscription, make sure you select the one you want to use.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az account <span class="built_in">set</span> --subscription YourSubscriptionId</span><br></pre></td></tr></table></figure>
<h2 id="Create_a_Resource_Group">Create a Resource Group</h2><p>You will need a resource group for your Storage and CDN resources. If you don’t already have one, create it here.<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az group create --name DavesFunctionApps --location WestUS2</span><br></pre></td></tr></table></figure></p>
<p>Most commands will require you to pass in a <code>--resource-group</code> and <code>--location</code> parameters. These parameters are <code>-g</code> and <code>-l</code> for short, but you can save yourself even more keystrokes by setting defaults for <code>az</code>.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az configure <span class="operator">-d</span> group=DavesFunctionApps</span><br><span class="line">az configure <span class="operator">-d</span> location=WestUS2</span><br></pre></td></tr></table></figure>
<h2 id="Creating_a_(temporary)_Premium_Hosting_Plan">Creating a (temporary) Premium Hosting Plan</h2><p>There is a strange requirement with Azure Functions / App Service. As per Jeff Hollan’s sample:</p>
<blockquote><p>The Azure Functions Premium plan is only available in a sub-set of infrastructure in each region. Internally we call these “webspaces” or “stamps.” You will only be able to move your function between plans if the webspace supports both consumption and premium. To make sure your consumption and premium functions land in an enabled webspace you should create a premium plan in a new resource group. Then create a consumption plan in the same resource group. You can then remove the premium plan. This will ensure the consumption function is in a premium-enabled webspace.</p>
<footer><strong>Jeff Hollan</strong><cite><a href="https://github.com/Azure-Samples/functions-csharp-premium-scaler" target="_blank" rel="external">github.com/Azure-Samples/functions-csharp-premium-scaler</a></cite></footer></blockquote>
<p>First, add an Azure Functions Premium plan to the resource group.<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp plan create -n dave_temp_premium_plan --sku EP1 --min-instances <span class="number">1</span></span><br></pre></td></tr></table></figure></p>
<p>You can delete this premium plan using the command below <em>after</em> you’ve deployed a function app to this resource group . <strong>Don’t forget to delete the premium plan. These cost $$$</strong></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp plan delete -n dave_temp_premium_plan</span><br></pre></td></tr></table></figure>
<h2 id="Creating_a_Function_App">Creating a Function App</h2><p>There are many options for creating a new function app. I really like the <code>func</code> command line tool which I installed using npm. Check out the <a href="https://github.com/Azure/azure-functions-core-tools" target="_blank" rel="external">Azure Functions Core Tools GitHub Repo</a> for details on other options for installing the <code>func</code> tooling.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">npm i -g azure-functions-core-tools@<span class="number">3</span> --unsafe-perm <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<p>The focus of this blog post is around scaling a function app. If you don’t already have an app built, you can follow along with <a href="https://docs.microsoft.com/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash" target="_blank" rel="external">this walkthrough</a> to create a function app.</p>
<p>A function app requires a Storage Account resource. An Application Insights resource is also highly recommended as this really simplifies monitoring your function app after it has been deployed. Let’s go ahead and create those 2 resources.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az storage account create -n davefuncappstorage</span><br><span class="line">az extension add -n application-insights</span><br><span class="line">az monitor app-insights component create --app davefuncappinsights</span><br></pre></td></tr></table></figure>
<p>Now we can create our Azure Function App resource with a consumption plan, passing in the name of the storage account and app insights resources that we just created. In my case, I’m specifying the dotnet runtime on a Windows host.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp create --consumption-plan-location WestUS2 --name davefuncapp123 --os-type Windows --runtime dotnet --storage-account davefuncappstorage --app-insights davefuncappinsights --functions-version <span class="number">3</span></span><br></pre></td></tr></table></figure>
<p>Remember to delete that temporary Premium Hosting Plan now!</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp plan delete -n dave_temp_premium_plan</span><br></pre></td></tr></table></figure>
<h3 id="Deploying_your_Function_App_using_the_az_cli">Deploying your Function App using the az cli</h3><p>This is a bit outside the scope of this blog post but I like using the <code>az</code> cli to deploy my function apps because it’s easy to incorporate that into my CI/CD pipelines. Since my app is using the dotnet runtime, I use the <code>dotnet publish</code> command to build the app.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">dotnet publish -c release</span><br></pre></td></tr></table></figure>
<p>Then, zip the contents of the publish folder (<code>bin\release\netcoreapp3.1\publish\</code>).</p>
<p>In PowerShell:<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">Compress-Archive -Path .\bin\release\netcoreapp3.<span class="number">1</span>\publish\* -DestinationPath .\bin\release\netcoreapp3.<span class="number">1</span>\package.zip</span><br></pre></td></tr></table></figure><br>or in Bash</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">zip -r ./bin/release/netcoreapp3.<span class="number">1</span>/package.zip ./bin/release/netcoreapp3.<span class="number">1</span>/publish/</span><br></pre></td></tr></table></figure>
<p>Finally, use the <code>az functionapp deployment</code> command to deploy the function app.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp deployment <span class="built_in">source</span> config-zip  -n davefuncapp123 --src ./bin/release/netcoreapp3.<span class="number">1</span>/package.zip</span><br></pre></td></tr></table></figure>
<h2 id="Scale_up_to_a_premium_plan">Scale up to a premium plan</h2><p>Okay, now that we have a functioning (pun intended) app deployed and running on a consumption plan, let’s see what it takes to scale this thing up to a premium plan.</p>
<p>First, create a new Premium Hosting Plan with the parameters that make sense for the load you are expecting. The <code>--sku</code> parameter refers to the size of the compute instance: EP1 is the smallest. The <code>--min-instancs</code> parameter is the number of pre-warmed instances that will always be running for this hosting plan. The <code>--max-burst</code> parameter is the upper bounds on the number of instances that the premium plan can elastically scale out if more instances are needed to handle load.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp plan create -n davefuncapp123_premium_plan --sku EP1 --min-instances <span class="number">4</span> --max-burst <span class="number">12</span></span><br></pre></td></tr></table></figure>
<p>Next, move the function app to that premium hosting plan.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp update --plan davefuncapp123_premium_plan -n davefuncapp123</span><br></pre></td></tr></table></figure>
<p>That’s it! All it took was those 2 command and your function app is now running on a premium plan!</p>
<h2 id="Scale_back_down_to_a_consumption_plan">Scale back down to a consumption plan</h2><p>Of course, that premium plan isn’t cheap. You might only want your function app running on the premium plan for a short period of time. Scaling back down is equally easy.</p>
<p>First, move the function app back to the consumption based plan. In my case, the name of the consumption plan is <code>WestUS2Plan</code>. You should see a consumption plan in your resource group. </p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp update --plan WestUS2Plan -n davefuncapp123</span><br></pre></td></tr></table></figure>
<p>Next, delete the premium hosting plan.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az functionapp plan delete -n davefuncapp123_premium_plan</span><br></pre></td></tr></table></figure>
<h2 id="Wrapping_it_up">Wrapping it up</h2><p>In this post, we saw how easy it is to move a function app between Premium and Consumption plans. A couple very simple <code>az</code> commands can help you get the performance and features of the Premium plan <em>only</em> when you need it while taking advantages of the simplicity and cost savings of a Consumption plan the rest of the time. </p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Azure Functions, when hosted on a consumption plan, are great for most scenarios. You pay per use which is great for keeping costs down b]]>
    </summary>
    
      <category term="AZ CLI" scheme="http://www.davepaquette.com/tags/AZ-CLI/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/tags/Azure/"/>
    
      <category term="Azure Functions" scheme="http://www.davepaquette.com/tags/Azure-Functions/"/>
    
      <category term="Web Dev" scheme="http://www.davepaquette.com/tags/Web-Dev/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/categories/Azure/"/>
    
      <category term="Azure Functions" scheme="http://www.davepaquette.com/categories/Azure/Azure-Functions/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Deploying a Static Site to Azure Using the az CLI]]></title>
    <link href="http://www.davepaquette.com/archive/2020/05/10/deploying-a-static-site-to-azure-using-the-az-cli.aspx"/>
    <id>http://www.davepaquette.com/archive/2020/05/10/deploying-a-static-site-to-azure-using-the-az-cli.aspx</id>
    <published>2020-05-10T22:30:00.000Z</published>
    <updated>2020-05-27T01:44:32.224Z</updated>
    <content type="html"><![CDATA[<p>I was recently working on a project where the frontend was built in React. The project was hosted on Azure and we wanted to use Azure CDN to host the React app. I have been looking at the az cli recently and decided to use it on this project to script the setup of resources and deployments to Azure.</p>
<h2 id="Setting_up_the_AZ_CLI">Setting up the AZ CLI</h2><p>First up, <a href="https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest" target="_blank" rel="external">install the az cli</a>.</p>
<p>Once installed, you’ll need to login to your Azure Subscription.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az login</span><br></pre></td></tr></table></figure>
<p>A browser window will popup, prompting you to log in to your Azure account. Once you’ve logged in, the browser window will close and the az cli will display a list of subscriptions available in your account. If you have more than one subscription, make sure you select the one you want to use.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az account <span class="built_in">set</span> --subscription YourSubscriptionId</span><br></pre></td></tr></table></figure>
<h2 id="Create_a_Resource_Group">Create a Resource Group</h2><p>You will need a resource group for your Storage and CDN resources. If you don’t already have one, create it here.<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az group create --name DavesFancyApp --location SouthCentralUs</span><br></pre></td></tr></table></figure></p>
<p>Most commands will require you to pass in a <code>--resource-group</code> and <code>--location</code> parameters. These parameters are <code>-g</code> and <code>-l</code> for short, but you can save yourself even more keystrokes by setting defaults for <code>az</code>.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az configure <span class="operator">-d</span> group=DavesFancyApp</span><br><span class="line">az configure <span class="operator">-d</span> location=SouthCentralUs</span><br></pre></td></tr></table></figure>
<h2 id="Create_a_Storage_Account_for_Static_Hosting">Create a Storage Account for Static Hosting</h2><p>First, create a storage account:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az storage account create --name davefancyapp123</span><br></pre></td></tr></table></figure>
<p>Then, enable static site hosting for this account.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az storage blob service-properties update --account-name davefancyapp123 --static-website --<span class="number">404</span>-document <span class="number">404</span>.html --index-document index.html</span><br></pre></td></tr></table></figure>
<p>Your storage account will now have a blob container named <code>$web</code>. That contents of that container will be available on the URL <em>accountname</em>.z21.web.core.windows.net/. For example, <code>https://davefancyapp123.z21.web.core.windows.net/</code>.</p>
<h2 id="Deploying_your_app">Deploying your app</h2><p>To deploy your app to the site, all you need to do is copy your app’s static files to the <code>$web</code> container in the storage account you created above. For my react app, that means running <code>npm run build</code> and copying the build output to the <code>$web</code> container. </p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az storage blob upload-batch --account-name davefancyapp123 <span class="operator">-s</span> ./build <span class="operator">-d</span> <span class="string">'$web'</span></span><br></pre></td></tr></table></figure>
<p>Now your site should be available via the static hosting URL above. That was easy!</p>
<h2 id="Create_a_CDN_Profile_and_Endpoint">Create a CDN Profile and Endpoint</h2><p>Next up, we are going to put a Content Delivery Network (CDN) endpoint in front of the blob storage account. We want to use a CDN for a couple reasons. First, it’s going to provide much better performance overall. CDNs are optimized for delivering web content to user’s devices and we should take advantage of that as much as possible. The second reason is that a CDN will allow us to configure SSL on a custom domain name.</p>
<p>First, we will need to create a CDN Profile. There are a few different of CDNs offerings available in Azure. You can read about them <a href="https://docs.microsoft.com/azure/cdn/cdn-features" target="_blank" rel="external">here</a>. In this example, we will us the Standard Microsoft CDN.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn profile create -n davefancyapp123cdn --sku Standard_Microsoft</span><br></pre></td></tr></table></figure>
<p>Next, we will create the CDN endpoint. Here we need to set the origin to the static hosting URL from the previous step. Note that we don’t include the protocol portion of the URL.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn endpoint create -n davefancyapp123cdnendpoint --profile-name davefancyapp123cdn --origin davefancyapp123.z21.web.core.windows.net --origin-host-header davefancyapp123.z21.web.core.windows.net --enable-compression</span><br></pre></td></tr></table></figure>
<p>Note: See the <a href="https://docs.microsoft.com/en-us/cli/azure/cdn/endpoint?view=azure-cli-latest#az-cdn-endpoint-create" target="_blank" rel="external">az cli docs</a> for more information on the options available when creating a CDN endpoint.</p>
<p>Now your site should be available from <em>endpointname</em>.azureedge.net. In my case <code>https://davefancyapp123cdnendpoint.azureedge.net/</code>. Note that the endpoint is created quickly but it can take some time for the actual content to propagate through the CDN. You might initially get a 404 when you visit the URL.</p>
<h3 id="Create_CDN_Endpoint_Rules">Create CDN Endpoint Rules</h3><p>These 2 steps are optional. The first one is highly recommended. The second is optional depending on the type of app your deploying. </p>
<p>First, create URL Redirect rule to redirect any HTTP requests to HTTPS.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn endpoint rule add -n davefancyapp123cdnendpoint --profile-name davefancyapp123cdn --rule-name enforcehttps --order <span class="number">1</span> --action-name <span class="string">"UrlRedirect"</span>  --redirect-type Found --redirect-protocol HTTPS --match-variable RequestScheme --operator Equal --match-value HTTP</span><br></pre></td></tr></table></figure>
<p>Next, if you’re deploying a Single Page Application (SPA) built in your favourite JavaScript framework (e.g. Vue, React, Angular), you will want a URL Rewrite rule that returns the app’s root <code>index.html</code> file for any request to a path that isn’t an actual file. There are many variations on how to write this rule. I found this to be the simplest one that worked for me. Basically if the request path is not for a specific file with a file extension, rewrite to <code>index.html</code>. This allows users to directly navigate to a route in my SPA and still have the CDN serve the <code>index.html</code> that bootstraps the application.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn endpoint rule add -n davefancyapp123cdnendpoint --profile-name davefancyapp123cdn --rule-name sparewrite --order <span class="number">2</span> --action-name <span class="string">"UrlRewrite"</span> --source-pattern <span class="string">'/'</span> --destination /index.html --preserve-unmatched-path <span class="literal">false</span> --match-variable UrlFileExtension --operator LessThan --match-value <span class="number">1</span></span><br></pre></td></tr></table></figure>
<h3 id="Configuring_a_domain_with_an_Azure_Managed_Certificate">Configuring a domain with an Azure Managed Certificate</h3><p>The final step in configuring the CDN Endpoint is to configure a custom domain and enable HTTPS on that custom domain.</p>
<p>You will need access to update DNS records for the custom domain. Add a CNAME record for your subdomain that points to the CDN endpoint URL. For example, I created a CNAME record on my davepaquette.com domain:</p>
<figure class="highlight stylus"><table><tr><td class="code"><pre><span class="line">CNAME    fancyapp   davefancyapp123cdnendpoint<span class="class">.azureedge</span><span class="class">.net</span></span><br></pre></td></tr></table></figure>
<p>Once the CNAME record has been created, create a custom domain for your endpoint. </p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn custom-domain create --endpoint-name davefancyapp123cdnendpoint --profile-name davefancyapp123cdn -n fancyapp-domain --hostname fancyapp.davepaquette.com</span><br></pre></td></tr></table></figure>
<p>And finally, enable HTTPs. Unfortunately, this step fails due to a <a href="https://github.com/Azure/azure-cli/issues/12152" target="_blank" rel="external">bug</a> in the AZ CLI. There’s <a href="https://github.com/Azure/azure-cli/pull/12648" target="_blank" rel="external">a fix</a> on it’s way for this but it hasn’t been merged into the CLI tool yet.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az cdn custom-domain <span class="built_in">enable</span>-https --endpoint-name davefancyapp123cdnendpoint --profile-name davefancyapp123cdn --name fancyapp-domain</span><br></pre></td></tr></table></figure>
<p>Due to the bug, this command returns <code>InvalidResource - The resource format is invalid</code>.  For now, you can <a href="https://docs.microsoft.com/en-us/azure/cdn/cdn-custom-ssl?tabs=option-1-default-enable-https-with-a-cdn-managed-certificate" target="_blank" rel="external">do this step manually</a> in the Azure Portal. When using CDN Managed Certificates, the process is full automated. Azure will verify your domain using the CNAME record above, provision a certificate and configure the CDN endpoint to use that certificate. Certificates are fully managed by Azure. That includes generating new certificates so you don’t need to worry about your certificate expiring.</p>
<h4 id="CDN_Managed_Certificates_for_Root_Domain">CDN Managed Certificates for Root Domain</h4><p>My biggest frustration with Azure CDN Endpoints is that CDN managed certificates are not supported for the apex/root domain. You can still use HTTPS but you need to bring your own certificate. </p>
<p>The same limitation exists for managed certificates on App Service. If you share my frustration, <a href="https://feedback.azure.com/forums/169385-web-apps/suggestions/38981932-add-naked-domain-support-to-app-service-managed-ce" target="_blank" rel="external">please upvote here</a>.</p>
<h2 id="Deploying_updates_to_your_application">Deploying updates to your application</h2><p>The CDN will cache your files. That’s great for performance but can be a royal pain when trying to deploy updates to your application. For SPA apps, I have found that simply telling the CDN to purge <code>index.html</code> is enough to ensure updates are available very shortly after deploying a new version. This works because most JavaScript frameworks today use WebPack which does a good job of cache-busting your JavaScript and CSS assets. You just need to make sure the browser is able to get the latest version of <code>index.html</code> and updates flow through nicely.</p>
<p>When you upload your latest files to blob storage, follow it with a purge command for <code>index.html</code> on the CDN endpoint.</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">az storage blob upload-batch --account-name davefancyapp123 <span class="operator">-s</span> ./build <span class="operator">-d</span> <span class="string">'$web'</span></span><br><span class="line">az cdn endpoint purge -n davefancyapp123cdnendpoint --profile-name davefancyapp123cdn --no-wait --content-paths <span class="string">'/'</span> <span class="string">'/index.html'</span></span><br></pre></td></tr></table></figure>
<p>The purge command can take a while to complete. We pass the <code>--no-wait</code> option so the command returns immediately. </p>
<h2 id="My_thoughts_on_az">My thoughts on az</h2><p>Aside from the bug I ran in to with enabling HTTPS on the CDN endpoint, I’ve really enjoyed my experience with the <code>az</code> cli. I was able to fully automate resource creation and deployments using the <a href="https://github.com/marketplace/actions/azure-cli-action" target="_blank" rel="external">GitHub Actions az cli action</a>. I can see <code>az</code> becoming my preferred method of managing Azure resources.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>I was recently working on a project where the frontend was built in React. The project was hosted on Azure and we wanted to use Azure CDN]]>
    </summary>
    
      <category term="AZ CLI" scheme="http://www.davepaquette.com/tags/AZ-CLI/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/tags/Azure/"/>
    
      <category term="Web Dev" scheme="http://www.davepaquette.com/tags/Web-Dev/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/categories/Azure/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Enhancing Application Insights Request Telemetry]]></title>
    <link href="http://www.davepaquette.com/archive/2020/03/07/enhancing-application-insights-request-telemetry.aspx"/>
    <id>http://www.davepaquette.com/archive/2020/03/07/enhancing-application-insights-request-telemetry.aspx</id>
    <published>2020-03-08T00:24:26.000Z</published>
    <updated>2020-05-12T02:02:47.204Z</updated>
    <content type="html"><![CDATA[<p>This post is a continuation of my series about using <a href="https://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-application-insights-for-net-core-apps.aspx">Application Insights in ASP.NET Core</a>. Today we will take a deeper dive into Request telemetry. </p>
<h1 id="Request_Telemetry">Request Telemetry</h1><p>For an ASP.NET Core process, the Application Insights SDK will automatically collect data about every request that the server process receives. This specific type of telemetry is called <a href="https://docs.microsoft.com/azure/azure-monitor/app/data-model-request-telemetry" target="_blank" rel="external">Request telemetry</a> and it contains a ton of very useful data including: the request path, the HTTP verb, the response status code, the duration, the timestamp when the request was received.   </p>
<p><img src="https://www.davepaquette.com/images/app_insights/request_telemetry.png" alt="Sample Request Telemetry"></p>
<p>The default data is great, but I often find myself wanting more information. For example, in a multi-tenant application, it would be very useful to track the tenant id as part of the request telemetry. This would allow us to filter data more effectively in the Application Insights portal and craft some very useful log analytics queries. </p>
<h1 id="Adding_custom_data_to_Request_Telemetry">Adding custom data to Request Telemetry</h1><p>All types of telemetry in Application Insights provide an option to store custom properties. In the <a href="https://www.davepaquette.com/archive/2020/02/05/setting-cloud-role-name-in-application-insights.aspx">previous post</a>, we saw how to create an <code>ITelemetryInitializer</code> to set properties on a particular telemetry instance. We could easily add custom properties to our Request telemetry using a telemetry initializer.</p>
<figure class="highlight cs"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">CustomPropertyTelemetryInitializer</span> : <span class="title">ITelemetryInitializer</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Initialize</span>(<span class="params">ITelemetry telemetry</span>)</span><br><span class="line">    </span>&#123;</span><br><span class="line">      requestTelemetry.Properties[<span class="string">"MyCustomProperty"</span>] = <span class="string">"Some Useful Value"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Any custom properties you add will be listed under Custom Properties in the Application Insights portal.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/request_telemetry_custom_property.png" alt="Sample Request Telemetry with Custom Properties"></p>
<p>But telemetry initializers are singletons and often don’t have access to the useful data that we want to add to request telemetry. Typically the data we want is related in some way to the current request and that data wouldn’t be available in a singleton service. Fortunately, there is another easy way to get an instance of the request telemetry for the current request. </p>
<figure class="highlight cs"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> requestTelemetry = HttpContext.Features.Get&lt;RequestTelemetry&gt;();</span><br><span class="line">requestTelemetry.Properties[<span class="string">"TenantId"</span>] = <span class="string">"ACME_CORP"</span>;</span><br></pre></td></tr></table></figure>
<p>You can do it anywhere you have access to an HTTP Context. Some examples I have seen include: <code>Middleware</code>, <code>ActionFilters</code>, <code>Controller</code> action methods, <code>OnActionExecuting</code> in a base <code>Controller</code> class and <code>PageModel</code> classes in Razor Pages. </p>
<h1 id="Filtering_by_Custom_Properties_in_the_Portal">Filtering by Custom Properties in the Portal</h1><p>Once you’ve added custom properties to Request Telemetry, you can use those custom properties to filter data in the Application Insights portal. For example, you might want to investigate failures that are occurring for a specific tenant or investigate performance for a particular tenant. </p>
<p><img src="https://www.davepaquette.com/images/app_insights/filer_by_custom_property.png" alt="Filtering by Custom Property"></p>
<p>This type of filtering can be applied almost anywhere in the portal and can help narrow things down when investigating problems.</p>
<h1 id="Writing_Useful_Log_Analytics_Queries">Writing Useful Log Analytics Queries</h1><p>Now this is where things get really interesting for me. What if we had one particular tenant complaining about performance. Wouldn’t it be interesting to plot out the average request duration for all tenants? We can easily accomplish this using a log analytics query.</p>
<figure class="highlight stata"><table><tr><td class="code"><pre><span class="line">requests</span><br><span class="line">| <span class="keyword">summarize</span> avg(duration) <span class="keyword">by</span> <span class="keyword">tostring</span>(customDimensions.TenantId), bin(timestamp, 15m)</span><br><span class="line">| render timechart</span><br></pre></td></tr></table></figure>
<p>This simple query will produce the following chart:</p>
<p><img src="https://www.davepaquette.com/images/app_insights/log_analytics_by_custom_property.png" alt="Log Analytics Query Summarize by Custom Property"></p>
<p>Small variations on this query can be extremely useful in comparing response times, failure rates, usage and pretty much anything else you can think of. </p>
<h1 id="Wrapping_it_up">Wrapping it up</h1><p>TenantId is just an example of a custom property. The custom properties that are useful for a particular application tend to emerge naturally as you’re investigating issues and sifting through telemetry in Application Insights. You will eventually find yourself saying “I wish I knew what <code>xxx</code> was for this request`. When that happens, stop and add that as a custom property to the request telemetry. You’ll thank yourself later.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>This post is a continuation of my series about using <a href="https://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-app]]>
    </summary>
    
      <category term=".NET" scheme="http://www.davepaquette.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://www.davepaquette.com/tags/NET-Core/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/tags/Application-Insights/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/tags/Azure/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/categories/Application-Insights/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Setting Cloud Role Name in Application Insights]]></title>
    <link href="http://www.davepaquette.com/archive/2020/02/05/setting-cloud-role-name-in-application-insights.aspx"/>
    <id>http://www.davepaquette.com/archive/2020/02/05/setting-cloud-role-name-in-application-insights.aspx</id>
    <published>2020-02-06T00:59:38.000Z</published>
    <updated>2020-05-12T02:02:47.203Z</updated>
    <content type="html"><![CDATA[<p>This post is a continuation of my series about using <a href="https://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-application-insights-for-net-core-apps.aspx">Application Insights in ASP.NET Core</a>. Today we will explore the concept of Cloud Role and why it’s an important thing to get right for your application.</p>
<p>In any application that involves more than a single server process/service, the concept of <em>Cloud Role</em> becomes really important in Application Insights. A Cloud Role roughly represents a process that runs somewhere on a server or possibly on a number of servers. A cloud role made up of 2 things: a <em>cloud role name</em> and a <em>cloud role instance</em>. </p>
<h2 id="Cloud_Role_Name">Cloud Role Name</h2><p>The cloud role name is a logical name for a particular process. For example, I might have a cloud role name of “Front End” for my front end web server and a name of “Weather Service” for a service that is responsible for providing weather data.</p>
<p>When a cloud role name is set, it will appear as a node in the Application Map. Here is an example showing a Front End role and a Weather Service role.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/example_application_map.png" alt="Application Map when Cloud Role Name is set "></p>
<p>However, when Cloud Role Name is not set, we end up with a misleading visual representation of how our services communicate.<br><img src="https://www.davepaquette.com/images/app_insights/example_application_map_no_cloud_role_name.png" alt="Application Map when Cloud Role Name is not set "></p>
<p>By default, the application insights SDK attempts to set the cloud role name for you. For example, when you’re running in Azure App Service, the name of the web app is used. However, when you are running in an on-premise VM, the cloud role name is often blank.</p>
<h2 id="Cloud_Role_Instance">Cloud Role Instance</h2><p>The cloud role instance tells us which specific server the cloud role is running on. This is important when scaling out your application. For example, if my Front End web server was running 2 instances behind a load balancer, I might have a cloud role instance of “frontend_prod_1” and another instance of “frontend_prod_2”. </p>
<p>The application insights SDK sets the cloud role instance to the name of the server hosting the service. For example, the name of the VM or the name of the underlying compute instance hosting the app in App Service. In my experience, the SDK does a good job here and I don’t usually need to override the cloud role instance.</p>
<h2 id="Setting_Cloud_Role_Name_using_a_Telemetry_Initializer">Setting Cloud Role Name using a Telemetry Initializer</h2><p>Telemetry Initializers are a powerful mechanism for customizing the telemetry that is collected by the Application Insights SDK. By creating and registering a telemetry initializer, you can overwrite or extend the properties of any piece of telemetry collected by Application Insights.</p>
<p>To set the Cloud Role Name, create a class that implements <code>ITelemetryInitializer</code> and in the <code>Initialize</code> method set the <code>telemetry.Context.Cloud.RoleName</code> to the cloud role name for the current application. </p>
<figure class="highlight cs"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">CloudRoleNameTelemetryInitializer</span> : <span class="title">ITelemetryInitializer</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Initialize</span>(<span class="params">ITelemetry telemetry</span>)</span><br><span class="line">    </span>&#123;</span><br><span class="line">      <span class="comment">// set custom role name here</span></span><br><span class="line">      telemetry.Context.Cloud.RoleName = <span class="string">"Custom RoleName"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Next, in the <code>Startup.ConfigureServices</code> method, register that telemetry initializer as a singleton.</p>
<figure class="highlight cs"><table><tr><td class="code"><pre><span class="line">services.AddSingleton&lt;ITelemetryInitializer, CloudRoleNameTelemetryInitializer&gt;();</span><br></pre></td></tr></table></figure>
<p>For those who learn by watching, I have recorded a video talking about using telemetry initializers to customize application insights.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/1OAaYb_HL5g?list=PLFHLo5Y9d4JaGXNF80SzymGTkbmED6VoO" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<h2 id="Using_a_Nuget_Package">Using a Nuget Package</h2><p>Creating a custom telemetry initializer to set the cloud role name is a simple enough, but it’s something I’ve done so many times that I decided to publish a <a href="https://www.nuget.org/packages/AspNetMonsters.ApplicationInsights.AspNetCore/" target="_blank" rel="external">Nuget package</a> to simplify it even further.</p>
<p>First, add the <code>AspNetMonsters.ApplicationInsights.AspNetCore</code> Nuget package:<br><figure class="highlight stylus"><table><tr><td class="code"><pre><span class="line">dotnet add package AspNetMonsters<span class="class">.ApplicationInsights</span><span class="class">.AspNetCore</span></span><br></pre></td></tr></table></figure></p>
<p>Next, in call <code>AddCloudRoleNameInitializer</code> in your application’s <code>Startup.ConfigureServices</code> method:<br><figure class="highlight 1c"><table><tr><td class="code"><pre><span class="line">services.AddCloudRoleNameInitializer(<span class="string">"WeatherService"</span>);</span><br></pre></td></tr></table></figure></p>
<h2 id="Filtering_by_Cloud_Role">Filtering by Cloud Role</h2><p>Setting the Cloud Role Name / Instance is about a lot more than seeing your services laid out properly in the Application Map. It’s also really important when you starting digging in to the performance and failures tabs in the Application Insights portal. In fact, on most of the sections of the portal, you’ll see this Roles filter.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/roles_pill.png" alt="Roles pill"></p>
<p>The default setting is <em>all</em>. When you click on it, you have the option to select any combination of your application’s role names / instances. For example, maybe I’m only interested in the <em>FrontEnd</em> service and <em>WeatherService</em> that were running on the dave_yoga920 instance.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/roles_filter.png" alt="Roles filter"></p>
<p>These filters are extremely useful when investigating performance or errors on a specific server or within a specific service. The more services your application is made up of, the more useful and essential this filtering become. These filters really help focus in on specific areas of an application within the Application Insights portal.</p>
<h2 id="Next_Steps">Next Steps</h2><p>In this post, we saw how to customize telemetry data using telemetry initializers. Setting the cloud role name is a simple customization that can help you navigate the massive amount of telemetry that application insights collects. In the next post, we will explore a more in complex example of using telemetry initializers.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>This post is a continuation of my series about using <a href="https://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-app]]>
    </summary>
    
      <category term=".NET" scheme="http://www.davepaquette.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://www.davepaquette.com/tags/NET-Core/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/tags/Application-Insights/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/tags/Azure/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/categories/Application-Insights/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Getting the Most Out of Application Insights for .NET (Core) Apps]]></title>
    <link href="http://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-application-insights-for-net-core-apps.aspx"/>
    <id>http://www.davepaquette.com/archive/2020/01/20/getting-the-most-out-of-application-insights-for-net-core-apps.aspx</id>
    <published>2020-01-20T16:50:18.000Z</published>
    <updated>2020-05-12T02:02:47.203Z</updated>
    <content type="html"><![CDATA[<p><a href="https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview" target="_blank" rel="external">Application Insights</a> is a powerful and surprisingly flexible application performance monitoring (APM) service hosted in Azure. Every time I’ve used Application Insights on a project, it has opened the team’s eyes to what is happening with our application in production. In fact, this might just be one of the best named Microsoft products ever. It literally provides <strong>insights</strong> into your <strong>applications</strong>.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/example_application_map.png" alt="Application Map provides a visual representation of your app&#39;s dependencies "></p>
<p>Application Insights has built-in support for .NET, Java, Node.js, Python, and Client-side JavaScript based applications. This blog post is specifically about .NET applications. If you’re application is built in another language, head over to the <a href="https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview" target="_blank" rel="external">docs</a> to learn more. </p>
<h2 id="Codeless_Monitoring_vs_Code-based_Monitoring">Codeless Monitoring vs Code-based Monitoring</h2><p>With codeless monitoring, you can configure a monitoring tool to run on the server (or service) that is hosting your application. The monitoring tool will monitor running processes and collect whatever information is available for that particular platform. There is built in support for <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/azure-vm-vmss-apps" target="_blank" rel="external">Azure VM and scale sets</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/azure-web-apps" target="_blank" rel="external">Azure App Service</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/cloudservices" target="_blank" rel="external">Azure Cloud Services</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring" target="_blank" rel="external">Azure Functions</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/monitor-performance-live-website-now" target="_blank" rel="external">Kubernetes applications</a> and <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/status-monitor-v2-overview" target="_blank" rel="external">On-Premises VMs</a>. Codeless monitoring is a good option if you want to collect information for applications that have already been built and deployed, but you are generally going to get more information using Code-based monitoring.</p>
<p>With code-based monitoring, you add the Application Insights SDK. The steps for adding the SDK are well document for <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core" target="_blank" rel="external">ASP.NET Core</a>, <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net" target="_blank" rel="external">ASP.NET</a>, and <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/console" target="_blank" rel="external">.NET Console</a> applications so I don’t need to re-hash that here.</p>
<p>If you prefer, I have recorded a video showing how to add Application Insights to an existing ASP.NET Core application.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/C4G1rRgY9OI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<h2 id="Telemetry">Telemetry</h2><p>Once you’ve added the Application Insights SDK to your application, it will start collecting telemetry data at runtime and sending it to Application Insights. That telemetry data is what feeds the UI in the Application Insights portal. The SDK will automatically collection information about your dependencies calls to SQL Server, HTTP calls and calls to many popular Azure Services. It’s the dependencies that often are the most insightful. In a complex system it’s difficult to know exactly what dependencies your application calls in order to process an incoming request. With App Insights, you can see exactly what dependencies are called by drilling in to the End-to-End Transaction view.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/end-to-end-transaction-view.png" alt="End-to-end transaction view showing an excess number of calls to SQL Server"></p>
<p>In addition to dependencies, the SDK will also collect requests, exceptions, traces, customEvents, and performanceCounters. If your application has a web front-end and you add the JavaScript client SDK, you’ll also find pageViews and browserTimings. </p>
<h2 id="Separate_your_Environments">Separate your Environments</h2><p>The SDK decides which Application Insights instance to send the collected telemetry based on the configured Instrumentation Key.</p>
<p>In the ASP.NET Core SDK, this is done through app settings:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"ApplicationInsights"</span>: &#123;</span><br><span class="line">    <span class="string">"InstrumentationKey"</span>: <span class="string">"ccbe3f84-0f5b-44e5-b40e-48f58df563e1"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>When you’re diagnosing an issue in production or investigating performance in your production systems, you don’t want any noise from your development or staging environments. I always recommend creating an Application Insights resource per environment. In the Azure Portal, you’ll find the instrumentation key in the top section of the Overview page for your Application Insights resource. Just grab that instrumentation key and add it to your environment specific configuration.</p>
<h2 id="Use_a_single_instance_for_all_your_production_services">Use a single instance for all your production services</h2><p>Consider a micro-services type architecture where your application is composed of a number of services, each hosted within it’s own process. It might be tempting to have each service point to a separate instance of Application Insights.</p>
<p>Contrary to the guidance of separating your environments, you’ll actually get the most value from Application Insights if you point all your related production services to a single Application Insights instance. The reason for this is that Application Insights automatically correlates telemetry so you can track a particular request across a series of separate services. That might sound a little like magic but it’s <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/correlation" target="_blank" rel="external">not actually as complicated as it sounds</a>.</p>
<p>It’s this correlation that allows the Application Map in App Insights to show exactly how all your services interact with each other.</p>
<p><img src="https://www.davepaquette.com/images/app_insights/detailed_application_map.png" alt="Application Map showing multiple services "></p>
<p>It also enables the end-to-end transaction view to show a timeline of all the calls between your services when you are drilling in to a specific request.  </p>
<p>This is all contingent on all your services sending telemetry to the same Application Insights instance. The Application Insights UI in the Azure Portal has no ability to display this visualizations across multiple Application Insights instances. </p>
<h2 id="You_don’t_need_to_be_on_Azure">You don’t need to be on Azure</h2><p>I’ve often heard developers say “I can’t use Application Insights because we’re not on Azure”. Well, you don’t need to host your application on Azure to use Application Insights. Yes, you will need an Azure subscription for the Application Insights resource, but your application can be hosted anywhere. That includes your own on-premise services, AWS or any other public/private cloud.</p>
<h2 id="Next_Steps">Next Steps</h2><p>Out of the box, Application Insights provides a tremendous amount of value but I always find myself having to customize a few things to really get the most out of the telemetry. Fortunately, the SDK provides some useful extension points. My plan is to follow up this post with a few more posts that go over those customizations in detail. I also have started to create a <a href="https://github.com/AspNetMonsters/ApplicationInsights" target="_blank" rel="external">NuGet package</a> to simplify those customizations so stay tuned!</p>
<h2 id="*Update">*Update</h2><p>Other posts in this series:<br><a href="https://www.davepaquette.com/archive/2020/02/05/setting-cloud-role-name-in-application-insights.aspx">Setting Cloud Role Name</a><br><a href="https://www.davepaquette.com/archive/2020/03/07/enhancing-application-insights-request-telemetry.aspx">Enhancing Application Insights Request Telemetry</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview" target="_blank" rel="external">Application Insights</a]]>
    </summary>
    
      <category term=".NET" scheme="http://www.davepaquette.com/tags/NET/"/>
    
      <category term=".NET Core" scheme="http://www.davepaquette.com/tags/NET-Core/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/tags/Application-Insights/"/>
    
      <category term="Azure" scheme="http://www.davepaquette.com/tags/Azure/"/>
    
      <category term="Application Insights" scheme="http://www.davepaquette.com/categories/Application-Insights/"/>
    
  </entry>
  
</feed>
