Bit of Technology

  • Archive
  • About Me
    • Advertise
    • Disclaimer
  • Speaking
  • Contact

Azure Container Apps Monitoring and Observability with Application Insights – Part 8

September 9, 2022 By Taiseer Joudeh 3 Comments

Share this:

  • Share on X (Opens in new window) X
  • Share on LinkedIn (Opens in new window) LinkedIn
  • Share on Reddit (Opens in new window) Reddit
  • Share on Facebook (Opens in new window) Facebook
  • Email a link to a friend (Opens in new window) Email

This is the eighth part of Building Microservice Applications with Azure Container Apps and Dapr. The topics we’ll cover are:

  • Tutorial for building Microservice Applications with Azure Container Apps and Dapr – Part 1
  • Deploy backend API Microservice to Azure Container Apps – Part 2
  • Communication between Microservices in Azure Container Apps – Part 3
  • Dapr Integration with Azure Container Apps – Part 4
  • Azure Container Apps State Store With Dapr State Management API – Part 5
  • Azure Container Apps Async Communication with Dapr Pub/Sub API – Part 6
  • Azure Container Apps with Dapr Bindings Building Block – Part 7
  • Azure Container Apps Monitoring and Observability with Application Insights – (This Post)
  • Continuous Deployment for Azure Container Apps using GitHub Actions – Part 9
  • Use Bicep to Deploy Dapr Microservices Apps to Azure Container Apps – Part 10
  • Azure Container Apps Auto Scaling with KEDA – Part 11
  • Azure Container Apps Volume Mounts using Azure Files – Part 12
  • Integrate Health probes in Azure Container Apps – Part 13

Azure Container Apps Monitoring and Observability with Application Insights

When building a microservices application that consists of many distributed services that communicate with each other across different processes and use different infrastructure services (different message brokers, different databases, different 3rd party components, etc…) then having a mechanism to observe and trace from end to end is inevitable.

The good news that Azure Container Apps provides various built-in Monitoring and Observability features that help in understanding how are the various services are operating and performing. Those features will help to monitor and diagnose the state of your distributed services to improve performance and respond to critical problems.

The Azure Container Apps official documentation page talks thoroughly about observability features, so I will not cover them here.
From my personal experience while building this tutorial and during the development and test phases, the 2 features I relied on most were the Log streaming and Azure Monitor Log Analytics.

The official documentation page didn’t talk about how to configure Azure Container Apps and Azure Container Apps Environment with Application Insights, as well Azure Container Apps do not support Auto-Instrumentation for Application Insights, so in this post, I will be focusing on how we can integrate Application Insights into our microservices application.

The source code for this tutorial is available on GitHub. You can check the demo application too.

Application Insights overview

Application Insights is an offering from Azure Monitor that will help us to monitor all Azure Container Apps under the same Container App Environment and collect telemetry about the services within the solution, as well as understand the usage of the services and users’ engagement via integrated analytics tools.
What I mean by Telemetry here is the data collected to observe our application, it can be broken into three categories :

  1. Distributed Tracing: provides insights into the traffic between services involved in distributed transactions, think of when the Frontend Web App talks with the Backend Api App to insert or retrieve data. An application map of how calls are flowing between services is very important for any distributed application.
  2. Metrics: provide insights into the performance of a service and its resource utilization, think of the CPU and Memory utilization of the Backend Background processor, and how we can understand when we need to increase the number of replicas.
  3. Logging: provides insights into how code is executing and if errors have occurred.

So let’s get started and add Application Insights to our solution.

Provision a Workspace-based Application Insights Instance

We need to create one single Application Insights instance to be used for all the services telemetry within our application, to create the instance using Azure CLI script below:

PowerShell
1
2
3
4
5
6
7
8
9
10
11
  ## install the application-insights extension for the CLI
  az extension add -n application-insights
  
  ## Workspace crreated when creating Azure Container Apps Env
  $workspace = "/subscriptions/<SubscriptionId>/resourcegroups/<RsourceGroup>/providers/microsoft.operationalinsights/workspaces/<WorkSpaceName>"
  
  ##Create Application Insights instance
  $ai = $(az monitor app-insights component create -g $RESOURCE_GROUP -l $Location --app $taskstracker-ai --workspace $workspace)  | ConvertFrom-Json
  
  ## Get APPINSIGHTS INSTRUMENTATIONKEY
  $APPINSIGHTS_INSTRUMENTATIONKEY=$($ai.InstrumentationKey)

We are creating here a Workspace-based Application Insights resource as the “Classic” one will be out of support in 2024. So we are going to use the same Workspace we created when we provisioned the Azure Container App Environment in this previous post.

Next, we need to update the Azure Container App Environment we have created in this previous post, if you remember we used the CLI command az containerapp env create  (link for command properties) as the below script to create the Environment:

PowerShell
1
2
3
4
az containerapp env create `
  --name $ENVIRONMENT `
  --resource-group $RESOURCE_GROUP `
  --location $LOCATION

You can see that we didn’t provide the property --dapr-instrumentation-key when creating it, and unfortunately we can’t update this from the Azure CLI, there is an open issue on GitHub asking to add support for updating the Azure Container Apps Environment via the CLI.
So my recommendation is to set the property “dapr-instrumentation-key” when creating the ACA Environment as it is the property responsible for setting the instrumentation key of the Application Insights instance used by Dapr to export Service to Service communication telemetry, without it you will not be able to see the relation between microservices.

In our case we need to do the update, in order to do this we are going to use Bicep/ARM template, I’m going to cover in the future post in full detail how we are going to use Bicep to provision every component in the solution including the external components such as Azure Storage, Cosmos DB, Service bus, etc… it will be a detailed post to show you how Bicep will simplify the creation of Infrastructure as a Code (IaC) and will enable you to create and redeploy the entire solution with all configuration we have done manually by executing one command or running 1 single action from GitHub actions.

For this post, I will keep the description minimal so follow along with me to create a simple Bicep file used to update the Azure Container Apps Environment, to do so, from VS code add a new folder named “deploy” on the same root folder of our solution “TasksTracker.ContainerApps/deploy” and then add a new file named “updateacaEnvironment.bicep”.
You need to install a VS code extension named Bicep, so go ahead and install it as we are going to use it heavily in the next post.
Now open the file named “updateacaEnvironment.bicep” and paste the code below

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
param location string = resourceGroup().location
param environmentName string = 'tasks-tracker-containerapps-env'
param appInsightsName string = 'taskstracker-ai'
param logAnalyticsWorkspaceName string ='workspace-taskstrackerrgRItW'
 
resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
    name: appInsightsName
}
 
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' existing = {
  name: logAnalyticsWorkspaceName
}
 
resource environment 'Microsoft.App/managedEnvironments@2022-03-01' = {
  name: environmentName
  location: location
  properties: {
    daprAIInstrumentationKey:appInsights.properties.InstrumentationKey
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalyticsWorkspace.properties.customerId
        sharedKey: listKeys(logAnalyticsWorkspace.id, logAnalyticsWorkspace.apiVersion).primarySharedKey
      }
    }
  }
}

What we’ve done here is simple, we are getting a reference for the existing Application Insights and Log Analytics Workspace instances, then, we are updating the existing Azure Container Apps Environment, see how we are setting the property “daprAIInstrumentationKey” on the highlighted line above, and providing the Application Insights Instrumentation Key.

To execute this file, use the PowerShell terminal and run the command below:

PowerShell
1
2
3
4
## Ensure you are on directory "~/asksTracker.ContainerApps"
az deployment group create `
  --resource-group $RESOURCE_GROUP `
  --template-file ./deploy/updateacaEnvironment.bicep

Installing Application Insights SDK into the 3 Microservices apps

Now we need to add Application Insights SDK to the 3 services we have, this is an identical operation, so I will describe how we can do it on the Backend API and you do the same on the remaining services.

Step 1: Install the Application Insights SDK using NuGet

To add the SDK, open the file “TasksTracker.TasksManager.Backend.Api.csproj” and add the below NuGet reference

XHTML
1
2
3
4
  <ItemGroup>
    <!--Other packages are removed for brevity-->
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
  </ItemGroup>

Step 2: Set RoleName property for all the services

Next and on each project, we will add a new file named “AppInsightsTelemetryInitializer.cs” on the root directory of the project, so add a file named “AppInsightsTelemetryInitializer.cs” under project “TasksTracker.TasksManager.Backend.Api.Svc” and paste the below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace TasksTracker.TasksManager.Backend.Api
{
    public class AppInsightsTelemetryInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {
            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
            {
                //set custom role name here
                telemetry.Context.Cloud.RoleName = "tasksmanager-backend-api";
            }
        }
    }
}

The only difference between each file on the 3 projects is the RoleName property value, this property will be used by Application Insights to identify the components on the application map, as well for example it will be useful for us if we need to filter on all the warning logs generated from the Backend API project, so we will use the value “tasksmanager-backend-api” when we filter.
You can check the RoleName value used in the project “TasksTracker.WebPortal.Frontend.Ui” and project “TasksTracker.Processor.Backend.Svc“.

Next, we need to register this “AppInsightsTelemetryInitializer” class, to do this, open the file “Program.cs” and add the code highlighted below (lines 5-9), don’t forget that you need to do the same for the remaining 2 projects.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
//Code removed for brevity
 
builder.Services.AddControllers();
 
builder.Services.AddApplicationInsightsTelemetry();
 
builder.Services.Configure<TelemetryConfiguration>((o) => {
    o.TelemetryInitializers.Add(new AppInsightsTelemetryInitializer());
});
 
var app = builder.Build();
 
//Code removed for brevity

Step 3: Set the Application Insights instrumentation key in appsettings.json file

Now we need to set the Application Insights Instrumentation Key so the projects are able to send telemetry data to the AI instance, to do this open file “appsettings.json” and paste the code below, we are going to set this via secrets and environment variables once we redeploy the Container Apps and create new revisions.

JavaScript
1
2
3
4
5
{
  "ApplicationInsights": {
    "InstrumentationKey": ""
  }
}

With this step we have completed the changes on the projects, let’s now deploy the changes and create new revisions.

Deploy the 3 services to Azure Container Apps and create new Revisions

Step 1: Add Application Insights Insrumnation key as a secret

Let’s create a secret named “appinsights-key” on each Container App which contains the value of the AI instrumentation key, remember that we can obtain this value from Azure Portal by going to AI instance we created or we can get it from Azure CLI as we did above. To create the secret use PowerShell console and paste the code below:

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
az containerapp secret set `
--name $BACKEND_API_NAME `
--resource-group $RESOURCE_GROUP `
--secrets "appinsights-key=<AI Key Here>"
 
az containerapp secret set `
--name $FRONTEND_WEBAPP_NAME `
--resource-group $RESOURCE_GROUP `
--secrets "appinsights-key=<AI Key Here>"
 
az containerapp secret set `
--name $BACKEND_SVC_NAME `
--resource-group $RESOURCE_GROUP `
--secrets "appinsights-key=<AI Key Here>"

Step 2: Build new images and push them to ACR

As we have done previously we need to build and push the 3 apps images to ACR so they are ready to be deployed to Azure Container Apps, to do so, continue using the same PowerShell console and paste the code below (Make sure you are on directory “TasksTracker.ContainerApps”):

PowerShell
1
2
3
4
5
6
7
8
## Build Backend API on ACR and Push to ACR
az acr build --registry $ACR_NAME --image "tasksmanager/$BACKEND_API_NAME" --file 'TasksTracker.TasksManager.Backend.Api/Dockerfile' .
 
## Build Backend Service on ACR and Push to ACR
az acr build --registry $ACR_NAME --image "tasksmanager/$BACKEND_SVC_NAME" --file 'TasksTracker.Processor.Backend.Svc/Dockerfile' .
 
## Build Frontend Web App on ACR and Push to ACR
az acr build --registry $ACR_NAME --image "tasksmanager/$FRONTEND_WEBAPP_NAME" --file 'TasksTracker.WebPortal.Frontend.Ui/Dockerfile' .

Step 3: Deploy new revisions of the 3 services to Azure Container Apps and set a new environment variable

As we’ve done multiple times, we need to update the Azure Container App hosting the 3 services with a new revision so our code changes are available for end users, to do so run the below PowerShell script, n and notice how we used the property --set-env-vars to set new environment variable named “ApplicationInsights__InstrumentationKey” and its value is a secret reference coming from the secret “appinsights-key” we added in step 1.

PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
az containerapp update `
--name $BACKEND_API_NAME  `
--resource-group $RESOURCE_GROUP `
--image taiseerjoudeh/tasksmanager-backend-api-repo:latest `
--revision-suffix v20220908-1 `
--cpu 0.25 --memory 0.5Gi `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key" `
--min-replicas 1 `
--max-replicas 2
 
az containerapp update `
--name $FRONTEND_WEBAPP_NAME  `
--resource-group $RESOURCE_GROUP `
--revision-suffix v20220908-1 `
--cpu 0.25 --memory 0.5Gi `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key" `
--min-replicas 1 `
--max-replicas 1
 
az containerapp update `
--name $BACKEND_SVC_NAME `
--resource-group $RESOURCE_GROUP `
--revision-suffix v20220908-1 `
--cpu 0.25 --memory 0.5Gi `
--set-env-vars "ApplicationInsights__InstrumentationKey=secretref:appinsights-key" `
--min-replicas 1 `
--max-replicas 5

With those changes in place, you should start seeing telemetry coming to the Application Insights instance provisioned, let’s review Application Insights key dashboards and panels in Azure Portal.

Distributed Tracing via Application Map

Application Map will help us to spot any performance bottlenecks or failure hotspots across all our services of our distributed microservices application. Each node on the map represents an application component (service) or its dependencies and has a health KPI and alerts status.

Distributed Tracing Application Insights

Looking at the image above, you will see for example how the Backend Api with could RoleName “tasksmanager-backend-api” is depending on the Cosmos DB instance, showing the number of calls and average time to service these calls. The application map is interactive so you can select a service/ component and drill down into details. For example, when I drill down into the Dapr State node to understand how many times my backend API invoked the Dapr Sidecar state service to Save/Delete state, you will see results similar to the below image:

Distributed Tracing Application Insights Details

Mintor production application using Live Metrics

This is one of my favorite monitoring panels, it provides you with near real-time (1-second latency) status of your entire distributed application, we can see performance and failures count, we can watch exceptions and traces as they happened, and we can see live servers (replicas in our case) and the CPU and Memory utilization and the number of requests they are handling.
These live metrics provide very powerful diagnostics for our production microservice application. Check the image below and see the server names and some requests coming to the system.

Live Metrics Application Insights

Logs search using Transaction Search

Transaction search in Application Insights will help us to find and explore individual telemetry items, such as exceptions, web requests, or dependencies. As well as any log traces and events that we’ve added to the application.
For example, if I want to see all the event types of type “Request” for the cloud RoleName “tasksmanager-backend-api” in the past 24 hours, I can use the transaction search dashboard to do this, see how the filters are set and the results are displayed nicely, you can drill down on each result to have more details and what telemetry was captured before and after. A very useful feature when troubleshooting exceptions and reading logs.
Transaction Search Application Insights.jpg

Failures and Performance Panels

The failure panel allows us to view the frequency of failures across different operations to help us to focus our efforts on those with the highest impact.

Failures Application Insights
The Performance panel displays performance details for the different operations in our system. By identifying those operations with the longest duration, we can diagnose potential problems or best target our ongoing development to improve the overall performance of the system

Performance Application Insights
In the next post, we will be implementing continuous integration and deployment so we automate the process of building images, pushing them to ACR, and then creating new revisions.

The source code for this tutorial is available on GitHub. You can check the demo application too.

Follow me on Twitter @tjoudeh

References:

  • The Dapr observability building block
  • Opentelemtry Overview
  • Application Map: Triage distributed applications
  • Find and diagnose performance issues with Azure Application Insights
  • Featured image credit by Bethany Drouin

Share this:

  • Share on X (Opens in new window) X
  • Share on LinkedIn (Opens in new window) LinkedIn
  • Share on Reddit (Opens in new window) Reddit
  • Share on Facebook (Opens in new window) Facebook
  • Email a link to a friend (Opens in new window) Email

Like this:

Like Loading…

Related Posts

  • Invoking Dapr Services in Azure Container Apps using gRPC – Part 2
  • gRPC Communication In Azure Container Apps – Part 1
  • Azure Container Apps Auto Scaling with KEDA – Part 11
  • Use Bicep to Deploy Dapr Microservices Apps to Azure Container Apps – Part 10
  • Continuous Deployment for Azure Container Apps using GitHub Actions – Part 9

Filed Under: Application Insights, ASP.NET 6, Azure Container Apps, Dapr, Microservices, Microservices Tagged With: Application Insights, ASP.NET 6, Azure, Azure Container Apps, Dapr, Microservice

Comments

  1. Drew says

    December 7, 2022 at 10:11 pm

    This series is really great, I appreciate these posts. I hope others find this as helpful as I have. Keep it up!

    Reply
    • Taiseer Joudeh says

      December 7, 2022 at 11:27 pm

      Thank you Drew for your comment, glad to hear this 🙌

      Reply
  2. Markus Barrett says

    May 7, 2024 at 2:37 pm

    Hi TAISEER,

    Thank you for an excellent series of posts! It has helped me quite a lot. And still does.
    Question though – When I run the updateacaEnvironment template deploy, it’s completed successfully. However, I cannot see the daprAIInstrumentationKey (or the daprAIConnectionString for that mather) being set on the enviornment. Neither through the cli (az containerapp env show.. ) nor through the azure portal JSON view. It always says null. I can see that other changes are pulling through, like adding tags for instance. Have you experienced this as well? I see that daprAIInstrumentationKey is marked as a “Sensitive value” (https://learn.microsoft.com/en-us/azure/templates/microsoft.app/managedenvironments?pivots=deployment-language-bicep#managedenvironmentproperties), could that have something to do with it?

    Best regards,
    Markus

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About Taiseer

Husband, Father, Consultant @ MSFT, Life Time Learner... Read More…

Buy me a coffeeBuy me a coffee

Recent Posts

  • Part 3: MCP Tools, Resources and Prompts in .NET
  • Part 2: Building Your First MCP Server in C#
  • Part 1: What is the Model Context Protocol? An Introduction for .NET Developers
  • Invoking Dapr Services in Azure Container Apps using gRPC – Part 2
  • gRPC Communication In Azure Container Apps – Part 1

Blog Archives

Recent Posts

  • Part 3: MCP Tools, Resources and Prompts in .NET
  • Part 2: Building Your First MCP Server in C#
  • Part 1: What is the Model Context Protocol? An Introduction for .NET Developers
  • Invoking Dapr Services in Azure Container Apps using gRPC – Part 2
  • gRPC Communication In Azure Container Apps – Part 1

Tags

.NET AI Agents AJAX AngularJS API API Versioning ASP.NET ASP.NET 6 Authentication Autherization Server Azure Azure Active Directory B2C Azure AD B2C Azure Container Apps Azure Storage C# Code First Dapr Dependency Injection Entity Framework Foursquare API GitHub Copilot jQuery JSON JSON Web Tokens JWT MCP Microservice Model Context Protocol Ninject OAuth OData Redis Resource Server REST RESTful Single Page Applications SPA Token Authentication Tutorial VS Code Web API Web API 2 Web API Security Web Service

Search

Copyright © 2026 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in

%d