Monsters Weekly 158 - Azure App Configuration

One of the services I forget about in Azure is Azure App Configuration. It allows you to maintain sets of variables across environment with ease. In this episode we’ll get a little into how to use it.

Monsters Weekly 157 - C# 8 Default Implementationss

Default implementations in C# 8 allow you to adapt your interfaces as your product changes without having to go back and fix a whole bunch of code you’ve already written.

Monsters Weekly 156 - Publishing to Nuget with GitHub Actions

In our continuing series about GitHub actions, we’re going to upload our package to NuGet thus automating our entire release process.

Monsters Weekly 155 - C# range operator

C# 8 adds a range operator to allow you to take slices of an array easily. In this episode, we’ll look at that and at array segments.

Enhancing Application Insights Request Telemetry

Originally posted to: https://www.davepaquette.com/archive/2020/03/07/enhancing-application-insights-request-telemetry.aspx

This post is a continuation of my series about using Application Insights in ASP.NET Core. Today we will take a deeper dive into Request telemetry.

Request Telemetry

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 Request telemetry 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.

Sample Request Telemetry

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.

Adding custom data to Request Telemetry

All types of telemetry in Application Insights provide an option to store custom properties. In the previous post, we saw how to create an ITelemetryInitializer to set properties on a particular telemetry instance. We could easily add custom properties to our Request telemetry using a telemetry initializer.

public class CustomPropertyTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
requestTelemetry.Properties["MyCustomProperty"] = "Some Useful Value";
}
}

Any custom properties you add will be listed under Custom Properties in the Application Insights portal.

Sample Request Telemetry with Custom Properties

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.

var requestTelemetry = HttpContext.Features.Get<RequestTelemetry>();
requestTelemetry.Properties["TenantId"] = "ACME_CORP";

You can do it anywhere you have access to an HTTP Context. Some examples I have seen include: Middleware, ActionFilters, Controller action methods, OnActionExecuting in a base Controller class and PageModel classes in Razor Pages.

Filtering by Custom Properties in the Portal

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.

Filtering by Custom Property

This type of filtering can be applied almost anywhere in the portal and can help narrow things down when investigating problems.

Writing Useful Log Analytics Queries

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.

requests
| summarize avg(duration) by tostring(customDimensions.TenantId), bin(timestamp, 15m)
| render timechart

This simple query will produce the following chart:

Log Analytics Query Summarize by Custom Property

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.

Wrapping it up

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 xxx was for this request`. When that happens, stop and add that as a custom property to the request telemetry. You’ll thank yourself later.

Monsters Weekly 154 - Integration Testing in ASP.NET Core with Alba

In this continuation of Episode #152 (https://youtu.be/GBKBCr6SjPs), Dave uses the GitHub Actions release trigger to generate a release version of a NuGet package that links back to the release notes on GitHub.

Monsters Weekly 153 - Releasing NuGet Packages with GitHub Actions

In this continuation of Episode #152 (https://youtu.be/GBKBCr6SjPs), Dave uses the GitHub Actions release trigger to generate a release version of a NuGet package that links back to the release notes on GitHub.

Monsters Weekly 152 - GitHub Actions and .NET Core

GitHub Actions makes it really easy to setup a continuous integration build for your .NET Core projects. In this episode, Dave shows us how to configure a workflow to build and test your .NET Core projects using a GitHub Actions workflow that is triggered on commits to master or on pull requests to master.

Monsters Weekly 151 - Visual Studio Code, .NET and Linux

Building .NET Core applications on Linux is much more enjoyable when using Visual Studio Code.
In this episode, Dave takes us through the basics of building and debugging .NET Core applications on Linux using Visual Studio Code

Setting Cloud Role Name in Application Insights

Originally posted to: https://www.davepaquette.com/archive/2020/02/05/setting-cloud-role-name-in-application-insights.aspx

This post is a continuation of my series about using Application Insights in ASP.NET Core. Today we will explore the concept of Cloud Role and why it’s an important thing to get right for your application.

In any application that involves more than a single server process/service, the concept of Cloud Role 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 cloud role name and a cloud role instance.

Cloud Role Name

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.

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.

Application Map when Cloud Role Name is set

However, when Cloud Role Name is not set, we end up with a misleading visual representation of how our services communicate.
Application Map when Cloud Role Name is not set

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.

Cloud Role Instance

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”.

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.

Setting Cloud Role Name using a Telemetry Initializer

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.

To set the Cloud Role Name, create a class that implements ITelemetryInitializer and in the Initialize method set the telemetry.Context.Cloud.RoleName to the cloud role name for the current application.

public class CloudRoleNameTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
// set custom role name here
telemetry.Context.Cloud.RoleName = "Custom RoleName";
}
}

Next, in the Startup.ConfigureServices method, register that telemetry initializer as a singleton.

services.AddSingleton<ITelemetryInitializer, CloudRoleNameTelemetryInitializer>();

For those who learn by watching, I have recorded a video talking about using telemetry initializers to customize application insights.

Using a Nuget Package

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 Nuget package to simplify it even further.

First, add the AspNetMonsters.ApplicationInsights.AspNetCore Nuget package:

dotnet add package AspNetMonsters.ApplicationInsights.AspNetCore

Next, in call AddCloudRoleNameInitializer in your application’s Startup.ConfigureServices method:

services.AddCloudRoleNameInitializer("WeatherService");

Filtering by Cloud Role

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.

Roles pill

The default setting is all. 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 FrontEnd service and WeatherService that were running on the dave_yoga920 instance.

Roles filter

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.

Next Steps

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.