The previous two lessons gave you the infrastructure view: how much CPU the VMSS is using, how many 5xx errors the website returns, which logs each resource has written. That answers "is the system healthy?", but not "what happened to the passenger with booking reference XR7742?". There is a gap between those two questions: the infrastructure can be in perfect shape and the passenger still be without their boarding pass.
Application Insights fills that gap. It is the part of Azure Monitor that observes the application from the inside: every request with its duration and its result, every call to the database, every exception with its stack, and — the decisive part — the thread that ties all of it together across the six components a booking passes through. This lesson teaches you how to instrument it, how to correlate it, how not to bankrupt yourself on volume, and how to get business data out of it, not just technical data.
Contents
- What it adds over infrastructure metrics
- The telemetry model
- Instrumentation: auto-instrumentation, SDK and workspace-based resource
- Distributed correlation: the thread that ties the booking together
- Application map, transactions and live metrics
- Performance, dependencies and failures
- Sampling: indispensable and treacherous
- Custom telemetry, initializers and processors
- Availability tests
- Smart detection and application alerts
- Querying the telemetry with KQL and controlling cost
- Common Mistakes and Tips
- Exercises
- Conclusion
- What it adds over infrastructure metrics
| Question | Answered by |
|---|---|
| Is the machine saturated? | Platform metrics (07-01) |
| What did the service write to its log? | Resource logs and KQL (07-02) |
| Which operation in my API is slow, and why? | Application Insights |
| Which external dependency is holding the request up? | Application Insights |
| How many distinct passengers have hit this error? | Application Insights |
| Where did this particular booking's flow break? | Application Insights |
The underlying difference is the subject of the measurement. Platform metrics measure resources; Application Insights measures business operations and users. That is why it can say "3.2% of purchase attempts fail at the boarding pass issuing step, affecting 148 distinct passengers in the last hour", a sentence no CPU metric can ever formulate.
- The telemetry model
Everything Application Insights collects fits into a handful of types. Knowing them is essential because each one has its own table in log-contoso-pro, its own cost and its own role in an investigation.
| Type | What it represents | Table | Example at Contoso |
|---|---|---|---|
| Request | Work the app does on somebody's behalf | AppRequests |
POST /api/reservas; a run of GenerarTarjetaEmbarque |
| Dependency | An outbound call to another system | AppDependencies |
A query to sql-contoso-reservas-pro, a write to cola-emision-tarjetas |
| Exception | An unhandled error, with a call stack | AppExceptions |
KeyVaultAccessDeniedException |
| Trace | A log message from the code | AppTraces |
"Fare recalculated for XR7742" |
| Custom event | A business fact that you emit | AppEvents |
ReservaConfirmada, CheckInCompletado |
| Custom metric | An aggregatable number that you emit | AppMetrics |
Average amount, free seats |
| Page view | A page load in the browser | AppPageViews |
The Contoso Bookings home page |
| Availability | The result of a synthetic test | AppAvailabilityResults |
A probe of /salud |
The key distinction, and the one most often confused: a request is inbound work, a dependency is outbound work. The same HTTP call between the website and the API appears twice: as a dependency on the website and as a request on the API. Correlating the two is what lets you see the whole journey.
- Instrumentation: auto-instrumentation, SDK and workspace-based resource
There are two ways to instrument, and they are not mutually exclusive:
| Automatic (codeless) | SDK in the code | |
|---|---|---|
| How it is enabled | A setting on the service | A NuGet package and configuration |
| What it collects | Requests, dependencies, exceptions, performance | All of the above plus whatever you emit |
| Redeployment | No need to touch the code | Requires a deployment |
| Business events | No | Yes |
| Where it fits at Contoso | The starting point on every service | app-contoso-reservas-pro and func-contoso-tarjetas-pro |
The practical recommendation is to start with the automatic one everywhere, and add the SDK only where you need business telemetry or fine-grained control.
First of all, the resource. Contoso uses a workspace-based resource, which sends all the telemetry to log-contoso-pro. That is what made section 7 of the previous lesson possible: the App* tables live alongside AzureDiagnostics and AzureActivity, and they can be cross-referenced in a single query. The classic, non-workspace-based resources kept the data separately and have been retired.
az monitor app-insights component create \
--app ai-insights-contoso-pro \
--resource-group rg-contoso-seguridad-pro \
--location westeurope \
--workspace "/subscriptions/<id>/resourceGroups/rg-contoso-seguridad-pro/providers/Microsoft.OperationalInsights/workspaces/log-contoso-pro" \
--application-type web \
--tags entorno=produccion proyecto=contoso-reservas centro-coste=CC-1042 propietario=marta.rios
# Codeless enablement on App Service (runtime extension)
CONN=$(az monitor app-insights component show --app ai-insights-contoso-pro \
--resource-group rg-contoso-seguridad-pro --query connectionString -o tsv)
az webapp config appsettings set \
--name app-contoso-reservas-pro --resource-group rg-contoso-reservas-pro \
--settings APPLICATIONINSIGHTS_CONNECTION_STRING="$CONN" \
ApplicationInsightsAgent_EXTENSION_VERSION="~3" \
XDT_MicrosoftApplicationInsights_Mode="recommended"About the connection string: it replaces the old instrumentation key and it is not optional, because on top of the identifier it carries the regional ingestion endpoints. It contains an identifier, not a data access credential, but it is still a configuration value: at Contoso it lives in kv-contoso-pro and reaches the application through a Key Vault reference, like any other setting (module 4).
Contoso's other two cases:
# Function: the same setting, plus host sampling configured in host.json
az functionapp config appsettings set \
--name func-contoso-tarjetas-pro --resource-group rg-contoso-reservas-pro \
--settings APPLICATIONINSIGHTS_CONNECTION_STRING="$CONN"
# Containers: injected as an application environment variable
az containerapp update --name ca-motor-disponibilidad \
--resource-group rg-contoso-reservas-pro \
--set-env-vars APPLICATIONINSIGHTS_CONNECTION_STRING="$CONN"On cae-contoso-pro it is worth separating two things that overlap: the Container Apps environment already sends system logs and metrics to log-contoso-pro, whereas Application Insights contributes the application's requests, dependencies and correlation. They complement each other and both are needed to follow a booking end to end.
- Distributed correlation: the thread that ties the booking together
This is the heart of the lesson and the answer to the problem that opened the module. When a passenger buys, six components are involved. Without correlation, each one generates isolated telemetry and there is no way to know what belongs to which purchase.
The solution is the W3C Trace Context, a standard Azure implements: every outbound call carries a traceparent header with the format 00-<trace-id>-<span-id>-<flags>. The receiver reads it, propagates it in its own calls and tags all of its telemetry with it. In the Log Analytics tables this shows up as three columns:
OperationId: identifies the complete business operation. It is the same value across all six components.Id: identifies the specific span, unique per component.ParentId: points at the span that caused it, and that is what builds the tree.
sequenceDiagram participant N as Browser participant W as app-contoso-reservas-pro participant A as app-contoso-api-disponibilidad-pro participant S as sql-contoso-reservas-pro participant Q as cola-emision-tarjetas participant F as func-contoso-tarjetas-pro N->>W: POST /reservas (new traceparent) W->>A: GET /api/disponibilidad (same OperationId) A->>S: SELECT ... (dependency) W->>Q: Enqueue message (traceparent in the message property) Q-->>F: Trigger F->>F: GenerarTarjetaEmbarque (same OperationId)
The fragile step is the queue. HTTP propagates traceparent on its own; messages do not, unless the sender writes it as a message property and the consumer reads it. Modern Service Bus SDKs do it automatically, but an Azure Storage queue such as cola-emision-tarjetas requires doing it by hand. If the trail is cut at the queue, the map splits in two and you are back where you started. Checking that is the first step of any rollout:
AppRequests
| where TimeGenerated > ago(1h) and AppRoleName == "func-contoso-tarjetas-pro"
| summarize Total = count(), NoParent = countif(isempty(ParentId))
| extend OrphanPercent = round(100.0 * NoParent / Total, 1)A high percentage of runs with no ParentId means exactly that: correlation broken at the asynchronous hop.
- Application map, transactions and live metrics
Three tools used daily are built on top of that correlation:
- Application map: an automatically generated graph with every component, their calls, the volume, the average latency and the error percentage of each edge. It reveals three things nobody had ever drawn: dependencies you did not know existed, the one that is genuinely slow, and components nobody calls any more. At Contoso it exposed that the website was querying
cosmos-contoso-tarifas-protwice per booking because of a caching bug. - End-to-end transaction details: click a specific request and you get the waterfall timeline of everything that happened, with the duration of each span. A 4.2-second request breaks down into 120 ms on the website, 3.8 s waiting for
sql-contoso-reservas-proand 280 ms of serialization: the culprit is in plain sight, no guesswork. - Live metrics: telemetry with one-second latency and no sampling, which is also not stored and therefore not billed as ingestion. It is the deployment tool: Diego publishes to the
preproduccionslot, swaps, and watches requests, errors and dependencies live during the two critical minutes. If something spikes, he rolls back before an alert has even been evaluated.
- Performance, dependencies and failures
The performance view ranks operations by duration and lets you see the full distribution, not just the mean. The correct reading is always by percentiles: if p50 is 180 ms and p95 is 3,400 ms, you do not have a general performance problem, you have a problem with a subset of requests — usually those from one specific use case, or the ones hitting a lock.
The dependency breakdown is usually where the answer lives. The rule of thumb: in business applications, 80% of the latency is outside your code, in the database or in an external service. The failures view rounds it out with the failing response codes, the most frequent exceptions and the dependencies that fail.
- Sampling: indispensable and treacherous
An application with real traffic generates a volume of telemetry it makes no sense to store in full. Sampling keeps a fraction of the items and records how many each one represents.
| Type | Where it happens | Setting | Cost it saves |
|---|---|---|---|
| Adaptive | In the SDK, before sending | Automatic, by a target of items per second | Ingestion and bandwidth |
| Fixed-rate | In the SDK, a constant percentage | You set the percentage | Ingestion and bandwidth |
| Ingestion | In the service, on receipt | A percentage on the resource | Storage only |
Two properties have to be understood well. First: sampling is consistent per operation. If a request is kept, its dependencies, traces and exceptions are kept too; you will never see an orphaned trace. Second, and here is the trap: each retained item carries an ItemCount field with the number of items it represents. The portal views apply it for you, but your KQL queries do not:
// WRONG with sampling: it undercounts the real total
AppRequests | where TimeGenerated > ago(1h) | summarize count()
// RIGHT: weight by the sampling factor
AppRequests | where TimeGenerated > ago(1h) | summarize Estimated = sum(ItemCount)With 20% sampling, the first query returns 2,000 and the reality is 10,000. That discrepancy between the portal and a query of your own is one of the most common sources of confusion, and it is solved with sum(ItemCount). At Contoso, adaptive sampling is active on the website with a target of five items per second, and switched off on func-contoso-tarjetas-pro, because its volume is low and every single run matters individually. Exceptions are always excluded from sampling.
- Custom telemetry, initializers and processors
This is where Application Insights stops being a technical tool and starts answering business questions. The ReservaConfirmada event you used in KQL comes from here:
public class BookingService
{
private readonly TelemetryClient _telemetry;
public BookingService(TelemetryClient telemetry) => _telemetry = telemetry;
public async Task<Booking> ConfirmAsync(BookingRequest request)
{
var booking = await _repository.CreateAsync(request);
// Business event: properties to filter and group by, metrics to aggregate
_telemetry.TrackEvent("ReservaConfirmada",
properties: new Dictionary<string, string>
{
["localizador"] = booking.Reference, // enables SeguirLocalizador() from 07-02
["canal"] = request.Channel, // web, mobile, desk
["ruta"] = $"{booking.Origin}-{booking.Destination}",
["clase"] = booking.Class,
["entorno"] = "produccion"
},
metrics: new Dictionary<string, double>
{
["importe"] = (double)booking.Amount,
["pasajeros"] = booking.Passengers.Count,
["diasAntelacion"] = (booking.Departure - DateTime.UtcNow).TotalDays
});
return booking;
}
}Three deliberate decisions in that code. Properties are strings and are used to filter and group (by canal); metrics are numbers and are used to aggregate (avg(importe)). The localizador is included because it is the key to any investigation, and it is not personal data: it identifies a booking, not a person. And there is no passenger name, no email address and no identity document; that is intentional and the next block reinforces it.
Telemetry initializers add context to everything that is sent; processors filter or modify it before it is sent:
// Initializer: enriches every item with common context
public class ContosoInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
telemetry.Context.Cloud.RoleName = "app-contoso-reservas-pro";
if (telemetry is ISupportProperties props)
{
props.Properties["centroCoste"] = "CC-1042";
props.Properties["version"] = Environment.GetEnvironmentVariable("BUILD_ID");
}
}
}
// Processor: drops noise and strips personal data before it leaves the process
public class ContosoProcessor : ITelemetryProcessor
{
private readonly ITelemetryProcessor _next;
private static readonly Regex Email = new(@"[\w\.\-]+@[\w\.\-]+\.\w+", RegexOptions.Compiled);
public ContosoProcessor(ITelemetryProcessor next) => _next = next;
public void Process(ITelemetry item)
{
// 1. Do not store the health probes: they are half the volume and add nothing
if (item is RequestTelemetry r && r.Url?.AbsolutePath == "/salud") return;
// 2. Mask any email addresses that have slipped into messages or queries
if (item is TraceTelemetry t)
t.Message = Email.Replace(t.Message, "[email-removed]");
if (item is DependencyTelemetry d && d.Data is not null)
d.Data = Email.Replace(d.Data, "[email-removed]");
_next.Process(item);
}
}This processor does two different jobs and both of them matter. The first is about cost: dropping the probes to /salud, which at Contoso were 46% of the recorded requests. The second is about compliance, and it is worth saying plainly: application telemetry is a common destination for personal data leaks, because a logged SQL query or an exception message can carry an email address or an identity document inside it. Under the GDPR, that turns log-contoso-pro into a store of personal data, with its obligations around legal basis, minimization, retention period and the right to erasure — and deleting selectively in Log Analytics is slow and limited. Contoso's rule is categorical: personal data is stripped out before it leaves the process, in the processor, never afterwards. Business identifiers such as the booking reference, yes; people's identities, no.
- Availability tests
Availability tests are synthetic probes launched from several regions. They feed the first alert in the 07-01 table and they detect what no log can: that the application is fine but the DNS, the certificate or the routing on fd-contoso-global is not.
| Type | What it does | Use at Contoso |
|---|---|---|
| Standard URL check | One HTTP request, validating the code, the content and the certificate | The API's /salud, from 5 locations |
| Custom with TrackAvailability | Any logic you write and publish as a result | Checking that a test boarding pass can be issued end to end |
Three design rules. Use at least five locations and require three of them to fail before alerting: with a single location, a local network problem generates false alarms. Check the content, not just the 200 status code — a custom error page returns 200 perfectly happily. And validate the certificate expiry, which is exactly the case that caused the boarding pass incident.
- Smart detection and application alerts
Smart detection analyzes the telemetry automatically and flags anomalies without configuring thresholds: an abnormal rise in the error rate, latency degradation against the baseline, memory leaks, or a pattern of exceptions that starts right after a deployment. It is useful for what it discovers without anybody asking, but it does not replace explicit alerts: it does not know your SLOs or your business criticality. Treat it as a second opinion and point it at the ag-equipo-contoso group, not at the on-call one.
Contoso's explicit application alerts, over the Application Insights metrics: API p95 latency above 800 ms, a failed request rate above 2%, a response time on the sql-contoso-reservas-pro dependency above 1 second, and the availability of /salud. All of them built with what you learned in 07-01 and pointing at the action groups already defined.
- Querying the telemetry with KQL and controlling cost
Because the resource is workspace-based, everything above is queried with KQL in log-contoso-pro. An example that combines what you have learned:
// Real business impact of failures, by sales channel
let window = 24h;
AppEvents
| where TimeGenerated > ago(window) and Name == "ReservaConfirmada"
| extend Channel = tostring(Properties["canal"]),
Amount = todouble(Measurements["importe"])
| summarize Confirmed = sum(ItemCount), Revenue = sum(Amount * ItemCount) by Channel
| join kind=leftouter (
AppRequests
| where TimeGenerated > ago(window) and Name == "POST /api/reservas" and Success == false
| extend Channel = tostring(Properties["canal"])
| summarize Failed = sum(ItemCount) by Channel
) on Channel
| extend FailureRate = round(100.0 * Failed / (Confirmed + Failed), 2)
| project Channel, Confirmed, Failed, FailureRate, RevenueEur = round(Revenue, 0)
| order by Failed descNotice the systematic use of sum(ItemCount) instead of count() because of sampling, Measurements for the event's metrics as opposed to Properties for the strings, and the explicit join kind=leftouter. The result is a table Nuria Peña understands: how many bookings and how many euros per channel, and what percentage is being lost.
On cost, the warning from 07-02 applies in full, because telemetry is billed like any other ingestion in Log Analytics. The levers specific to Application Insights, in order of impact: adaptive sampling active on the high-volume services; filtering health probes and requests for static resources in the processor; switching off debug-level traces in production, which is the most expensive and most frequent mistake; and per-table retention, with AppTraces at 30 days and AppEvents kept longer for its business value. With those four measures Contoso reduced its volume by 60% without losing any investigative capability.
Common Mistakes and Tips
- Counting without
ItemCount. With sampling active,count()systematically undercounts. Usesum(ItemCount). - Correlation broken at the queue. If the
traceparentdoes not travel in the message, the trail breaks. Check it with the percentage of requests with noParentId. - Logging personal data. Email addresses and documents end up in traces and in logged queries. Filter them in the processor, before sending.
- Leaving the debug level on in production. The number one cause of runaway telemetry bills.
- An availability test from a single location. It generates false alarms; use five and require three to fail.
- Relying on smart detection alone. It does not know your SLOs; it complements, it does not replace.
- Tip: set
Cloud.RoleNamein an initializer. Without it, the application map shows generic names and stops being readable. - Tip: emit business events from day one. Technical instrumentation can be added later; reconstructing a business history you never captured cannot.
- Tip: use live metrics on every deployment. It is free, it is not sampled and it gives you a two-minute head start on any alert.
Exercises
Exercise 1. The website shows an average latency of 2.3 s towards sql-contoso-reservas-pro on the application map, but the database's metrics view reports DTU usage of 35% and no slow queries recorded. Explain the possible causes and how to tell them apart with the tools from this lesson.
Exercise 2. Diego has instrumented func-contoso-tarjetas-pro and can see its runs, but when he uses SeguirLocalizador("XR7742") from 07-02 the function does not appear in the timeline. Diagnose the problem and describe the fix.
Exercise 3. The Contoso Miles team (centro-coste=CC-2077) wants to measure how many members redeem points, the average redemption amount and what percentage abandon halfway through the process. Design the full instrumentation, including the KQL query and the privacy and cost precautions.
Solutions
Solution 1: there are three possible causes and they can be told apart cleanly. (a) The time is not in the database but in reaching it: connection pool exhaustion, DNS resolution or network latency. You identify it because in the end-to-end transaction details the dependency takes a long time but the query executed is trivial, and because AppDependencies shows a high duration with Success == true. (b) Blocking and waits: the query is fast but it is waiting on another transaction; DTU usage is low precisely because nobody is working, everybody is waiting. You confirm it with the Deadlocks and Timeouts logs from the SQL diagnostic setting (07-01). (c) A misleading average: a handful of very slow queries pull up the map's mean. You rule it out by querying AppDependencies with percentile(DurationMs, 50) and percentile(DurationMs, 95) grouped by Data: if p50 is low and p95 is sky-high, the problem affects one specific query and not the whole set. The order of investigation is always that: percentiles first, then the end-to-end transaction details of one specific slow case, and only then look at the database.
Solution 2: the correlation has broken at the asynchronous hop. The website writes to cola-emision-tarjetas, which is an Azure Storage queue and does not automatically propagate the W3C Trace Context, unlike HTTP or Service Bus. The function therefore starts a new operation, with its own OperationId, and SeguirLocalizador — which filters on OperationId == op — does not find it. Diagnosis: the query for requests with no ParentId from section 4 will return close to 100% for that function. Fix: include the traceparent as a message property when enqueueing and, in the function, start the activity with that context as its parent before emitting any telemetry. Verification: after the change, the application map should show the edge from the queue to the function, and the end-to-end timeline should reach GenerarTarjetaEmbarque. As a safety net in the meantime, adding the localizador as a property on all of the function's telemetry lets you find it by that field even if correlation fails.
Solution 3: instrumentation with three custom events — CanjeIniciado, CanjeConfirmado and CanjeAbandonado — all with the properties idCanje (an identifier of your own, not the member number), tipoPremio, paso and entorno, and the metrics puntos and importeEquivalente. The funnel is computed with AppEvents | where Name startswith "Canje" | summarize Total = sum(ItemCount) by Name, and abandonment as 1 - Confirmed/Started; the average amount, with summarize avg(todouble(Measurements["importeEquivalente"])) over the confirmed ones, always weighting by ItemCount. Privacy: the member number is not emitted, nor their name, nor their email; a redemption identifier with no external meaning is used instead, and the telemetry processor masks any email address that slips into traces or dependencies, in line with the GDPR and the lesson's policy. Cost: adaptive sampling switched off if the redemption volume is low — it is worth keeping every event — but debug traces switched off and health probes filtered; a generous retention on AppEvents for its business value and AppTraces at 30 days. Resource tags: entorno, proyecto=contoso-millas, centro-coste=CC-2077 and propietario.
Conclusion
You now know what Application Insights adds over infrastructure metrics: it changes the subject of the measurement, from resources to business operations and users. You know its telemetry model — request, dependency, exception, trace, custom event, custom metric, page view and availability — each with its own table, and the distinction that gets confused most often: a request is inbound work, a dependency is outbound work. You know how to instrument codelessly and with the SDK, and why Contoso uses a workspace-based resource that sends everything to log-contoso-pro, unifying this lesson with the previous one; you have enabled it on app-contoso-reservas-pro, on func-contoso-tarjetas-pro and on the containers in cae-contoso-pro, with the connection string kept in kv-contoso-pro.
The center of the lesson was distributed correlation: the W3C Trace Context, OperationId, Id and ParentId, and the fragile point of the asynchronous hop through the queue, which is exactly where the trail of the booking that opened the module was breaking. On top of that correlation you have seen the application map, the end-to-end transaction details that break a slow request down span by span, and live metrics for watching a deployment in real time and at no cost. You have mastered sampling — adaptive, fixed-rate and ingestion — why it is indispensable and the ItemCount trap that makes your queries undercount. You have emitted business custom telemetry in C#, and you have written an initializer that enriches and a processor that filters probes and strips personal data before it leaves the process, with the GDPR warning that this entails. And you close with availability tests from several locations, smart detection as a second opinion, the application alerts and cost control with the four levers that cut Contoso's volume by 60%.
With this, Contoso's platform is finally observable: a complaint becomes a query, and a query becomes a root cause. But observing is not operating. Every morning somebody switches the development environments on and every night somebody ought to switch them off; there are old snapshots nobody cleans up, credentials to rotate, reports to generate and servers to patch, and all of that keeps consuming the hours of Marta Ríos' team. Lesson 07-04, Azure Automation and Runbooks, deals with that repetitive work: Automation accounts with a managed identity, PowerShell runbooks with their schedules and their assets, Hybrid Runbook Workers to act on the Barcelona office, firing a runbook from an Azure Monitor alert — closing the loop with 07-01 — and Azure Update Manager for patching.
Azure Course
Module 1: Introduction to Azure
- What Is Azure?
- Service Models, Regions and Availability Zones
- Creating and Setting Up Your Azure Account
- A Tour of the Azure Portal
- Azure Resource Manager: Subscriptions, Resource Groups and Tags
- Azure CLI, PowerShell and Cloud Shell
Module 2: Core Azure Services
- Azure Virtual Machines
- Compute Scaling and High Availability
- Azure App Service
- Azure Storage: Blobs, Files, Queues and Tables
- Azure Networking: Virtual Networks, Subnets and NSGs
- Hybrid Connectivity and Global Delivery
Module 3: Azure Databases
- Choosing the Right Data Service
- Azure SQL Database
- Azure Cosmos DB
- Azure Database for MySQL
- Azure Database for PostgreSQL
- Data Analytics: Data Lake, Data Factory and Synapse
Module 4: Security in Azure
- Microsoft Entra ID and Identity Management
- RBAC and Managed Identities
- Azure Key Vault
- DDoS Protection and Web Application Firewall
- Microsoft Defender for Cloud
- Governance and Compliance with Azure Policy
Module 5: Azure DevOps
- Introduction to Azure DevOps
- Azure Repos
- Azure Pipelines: Continuous Integration
- Continuous Deployment with Environments and Approvals
- Azure Artifacts
- Infrastructure as Code with Bicep
Module 6: Advanced Azure Services
- Containers in Azure: Container Registry and Container Apps
- Azure Kubernetes Service (AKS)
- Azure Functions
- Azure Logic Apps
- Messaging and Events: Service Bus, Event Grid and Event Hubs
- Azure AI Services
Module 7: Monitoring and Management
- Azure Monitor: Metrics, Alerts and Dashboards
- Log Analytics and KQL Queries
- Application Insights
- Azure Automation and Runbooks
- Backup and Disaster Recovery
Module 8: Cost Management and Optimization
- Pricing Calculator and Cost Estimation
- Azure Cost Management: Analysis, Budgets and Alerts
- Reservations, Savings Plans and Azure Hybrid Benefit
- Azure Advisor
- Optimization Strategies and FinOps Culture
