Course: Azure Developer Associate (AZ-204) – Monitoring and Troubleshooting Applications
Module 1 – Exploring Azure Monitor
Why Instrument Your Applications?
- After a deployment, don’t wait for users to report issues.
- Instrumentation means adding code that generates data about the application’s behavior.
- Exam objective: Monitor and troubleshoot solutions by using Application Insights.
The 3 Pillars of Observability
| Pillar | Description |
|---|---|
| Logs | Text messages describing events. Stored in Log Analytics. |
| Traces | A series of logs tied to a single user request. Lets you follow the complete journey of a request. |
| Metrics | Numeric time-series data (e.g., CPU, memory, connected users). Also called performance counters. |
Azure Monitor vs. Application Insights vs. Log Analytics
- Log Analytics Workspace: Storage service for logs. All sources (activity log, resource logs, app) send their data here.
- Azure Monitor: Generic central hub for storing metrics and logs.
- Application Insights: Service optimized for instrumenting applications whose source code you control. Uses Azure Monitor as its backend.
- Connection App Insights → Azure Monitor: configured when the Application Insights instance is created.
- Connection Application → App Insights: via the connection string injected into the app configuration.
Diagnostic Settings
- Available on all Azure resources.
- Used to route logs to one or more Log Analytics Workspaces.
- Configuration: select desired logs + destination.
Demo: Create a Log Analytics Workspace
- Create the workspace (only required parameter: name, e.g.
all-demo-logs). - Configure a Diagnostic Setting on the subscription to send the Activity Log there.
- Use KQL (Kusto Query Language) to query data in Log Analytics.
Azure Service Health
- Monitors the health of the Azure platform itself.
- Resource Health: health of a specific resource (includes historical view).
- Service Health blade: overview of all active incidents for your resources.
- Helps distinguish whether a problem comes from your code or the Azure platform.
Module 2 – Application Insights In Depth
Application Insights Architecture
Application → Application Insights → Azure Monitor (backend)
↓
Engineer (query/troubleshoot)
3 Ways to Connect an App to Application Insights
| Method | Advantage | Disadvantage |
|---|---|---|
| Autoinstrumentation | Fast, no code changes | Less data |
| Application Insights SDK | Rich, customizable data | Requires a redeployment |
| OpenTelemetry Distro | Open standard, portable | More complex configuration |
Autoinstrumentation (Demo)
- Done without redeployment, directly from the Azure portal.
- In the App Service → Application Insights tab → enable monitoring.
- Azure automatically injects agents into the app.
- Generates data such as HTTP requests, dependencies, and exceptions.
Installing the Application Insights SDK (Demo)
- In Visual Studio: right-click the project → Connected Services → Add → Application Insights.
- The wizard installs NuGet packages and configures the code.
- The connection string is read from the application configuration.
- Use
ILogger(dependency injection) to emit custom logs.
// Example usage of ILogger
_logger.LogInformation("Processing request {RequestId}", requestId);
_logger.LogWarning("Item not found for ID {ItemId}", itemId);
_logger.LogError(ex, "Error while creating the order");
Types of Data Collected by Application Insights
- Requests: all HTTP requests received by the API.
- Dependencies: calls to external services (DB, third-party APIs, etc.).
- Exceptions: unhandled errors and traced exceptions.
- Traces: logs emitted via
ILoggeror the telemetry APIs. - Custom Metrics: custom metrics defined in code.
Main Views in Application Insights
- Live Metrics: real-time monitoring (live stream).
- Transaction Search: search for individual requests.
- Application Map: topological view of dependencies.
- Failures: analysis of errors and exceptions.
- Performance: response times by operation.
Web Tests and Availability Alerts
- URL Ping Test: simple test that verifies a URL responds with HTTP 200.
- Multi-step Web Test: sequence of HTTP requests simulating a user scenario.
- Standard Test: tests SSL, domain name, HTTP response.
- Tests run from multiple configurable geographic regions.
- Configure alerts on tests to be notified of failures.
Sampling
- For high-traffic applications, Application Insights can sample data.
- Reduces costs while maintaining a statistically valid representation.
- Types: Adaptive sampling (auto), Fixed-rate sampling, Ingestion sampling.
OpenTelemetry
- Open standard for observability (logs, traces, metrics).
- Microsoft is pushing OpenTelemetry as an alternative/complement to the proprietary SDK.
- The Azure Monitor Distro for OpenTelemetry sends data to Application Insights.
Module 3 – Alerts and Dashboards
Azure Monitor Alerts
- Triggered on metrics, logs, or activity signals.
- Components:
- Alert Rule: trigger condition.
- Action Group: list of actions to execute (email, SMS, webhook, Azure Function, etc.).
- Alert Instance: triggered occurrence.
- Severity: 0 (critical) → 4 (verbose).
Alert Types
| Type | Based on |
|---|---|
| Metric alert | A metric value crossing a threshold |
| Log alert | Result of a KQL query |
| Activity log alert | Events from the Azure activity log |
Dynamic Thresholds
- Machine learning that automatically calculates thresholds based on history.
- Advantage: adapts to seasonal variations (e.g., more traffic on Friday nights).
- Automatically configures thresholds instead of entering them manually.
Workbooks
- Interactive reports combining text, queries, and visualizations.
- Allow sharing analyses with stakeholders.
Key Points for the Exam
- Application Insights sits between the application and Azure Monitor.
- The 3 pillars: Logs, Traces, Metrics.
- Autoinstrumentation does not require a redeployment.
- Connection string (not Instrumentation Key) is the recommended method.
- Web tests require an App Service plan (not the Free plan).
- Azure Service Health for Azure platform health, Resource Health for a specific resource.
- Log Analytics stores data; Application Insights provides specialized views for applications.
Module 4 – Application Insights SDK Integration
SDK Architecture
flowchart LR
A[.NET Application] -->|TelemetryClient| B[TelemetryChannel]
B -->|HTTPS| C[Application Insights Endpoint]
C --> D["(Log Analytics Workspace)"]
D --> E[Azure Monitor]
subgraph SDK Concepts
F[TelemetryClient] --> G[TelemetryContext]
F --> H[TelemetryConfiguration]
H --> I[ITelemetryInitializer]
H --> J[ITelemetryProcessor]
end
TelemetryClient – Overview
The TelemetryClient is the central class of the SDK. It exposes methods for each type of telemetry:
| Method | Data Type | Table in Log Analytics |
|---|---|---|
TrackEvent() | Custom event | customEvents |
TrackMetric() | Custom metric | customMetrics |
TrackException() | Exception | exceptions |
TrackRequest() | HTTP request | requests |
TrackDependency() | Outbound call | dependencies |
TrackTrace() | Trace log | traces |
TrackAvailability() | Availability test | availabilityResults |
TrackPageView() | Page view (JS) | pageViews |
Installation and Configuration
// Required NuGet package
// Microsoft.ApplicationInsights.AspNetCore
// Program.cs – service registration
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplicationInsightsTelemetry(options =>
{
options.ConnectionString = builder.Configuration["ApplicationInsights:ConnectionString"];
options.EnableAdaptiveSampling = true;
options.EnableQuickPulseMetricStream = true; // Live Metrics
});
TrackEvent – Custom Events
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
public class OrderController : ControllerBase
{
private readonly TelemetryClient _telemetry;
public OrderController(TelemetryClient telemetry)
{
_telemetry = telemetry;
}
[HttpPost]
public async Task<IActionResult> CreateOrder(OrderDto dto)
{
// Event with custom properties
_telemetry.TrackEvent("OrderPlaced", new Dictionary<string, string>
{
{ "OrderId", dto.Id.ToString() },
{ "CustomerId", dto.CustomerId.ToString() },
{ "Region", dto.Region }
},
new Dictionary<string, double>
{
{ "OrderTotal", (double)dto.TotalAmount },
{ "LineItems", dto.Items.Count }
});
// ...
return Ok();
}
}
TrackMetric – Custom Metrics
// Direct method
_telemetry.TrackMetric("QueueDepth", queue.Count);
// Via GetMetric (recommended – aggregates before sending, reduces costs)
private readonly Metric _processingDuration;
public ProcessingService(TelemetryClient telemetry)
{
// Creates a metric with a "Priority" dimension
_processingDuration = telemetry.GetMetric(
new MetricIdentifier("ProcessingDuration", "Priority"));
}
public void ProcessItem(WorkItem item)
{
var sw = Stopwatch.StartNew();
// ... processing ...
sw.Stop();
_processingDuration.TrackValue(sw.ElapsedMilliseconds, item.Priority);
}
Exam tip:
GetMetric()is preferred overTrackMetric()because it pre-aggregates values on the client side and reduces the number of network calls.
TrackException – Exceptions
try
{
await _repository.SaveAsync(entity);
}
catch (SqlException ex)
{
_telemetry.TrackException(ex, new Dictionary<string, string>
{
{ "Operation", "SaveEntity" },
{ "EntityType", entity.GetType().Name },
{ "RecordId", entity.Id.ToString() }
});
throw; // re-throw to preserve the stack trace
}
TrackRequest – Manual Requests
// Useful for workers, background services, or queue messages
var startTime = DateTimeOffset.UtcNow;
var timer = Stopwatch.StartNew();
bool success = false;
try
{
await ProcessMessageAsync(message);
success = true;
}
finally
{
timer.Stop();
_telemetry.TrackRequest(
name: "ProcessQueueMessage",
startTime: startTime,
duration: timer.Elapsed,
responseCode: success ? "200" : "500",
success: success);
}
TrackDependency – Dependencies
var startTime = DateTimeOffset.UtcNow;
var timer = Stopwatch.StartNew();
bool success = false;
try
{
result = await _httpClient.GetAsync(externalApiUrl);
success = result.IsSuccessStatusCode;
}
finally
{
timer.Stop();
_telemetry.TrackDependency(
dependencyTypeName: "HTTP",
target: "api.external.com",
dependencyName: "GET /v1/data",
data: externalApiUrl.ToString(),
startTime: startTime,
duration: timer.Elapsed,
resultCode: result?.StatusCode.ToString() ?? "Timeout",
success: success);
}
TelemetryContext – Global Properties
// Add properties to ALL telemetry items via an Initializer
public class AppTelemetryInitializer : ITelemetryInitializer
{
private readonly IHttpContextAccessor _httpContext;
public AppTelemetryInitializer(IHttpContextAccessor httpContext)
{
_httpContext = httpContext;
}
public void Initialize(ITelemetry telemetry)
{
// Enrich each item with the tenant ID extracted from the JWT
var userId = _httpContext.HttpContext?.User?.FindFirst("sub")?.Value;
if (!string.IsNullOrEmpty(userId))
{
telemetry.Context.User.AuthenticatedUserId = userId;
}
// Global application properties
telemetry.Context.GlobalProperties["AppVersion"] = "2.4.1";
telemetry.Context.GlobalProperties["Environment"] = "Production";
}
}
// Registration in Program.cs
builder.Services.AddSingleton<ITelemetryInitializer, AppTelemetryInitializer>();
Sampling Configuration
builder.Services.AddApplicationInsightsTelemetry();
builder.Services.Configure<TelemetryConfiguration>(config =>
{
// Adaptive sampling (default) – adjusts rate automatically
var adaptiveSampling = new AdaptiveSamplingTelemetryProcessor(config)
{
MaxTelemetryItemsPerSecond = 5, // ceiling of items/s
MinSamplingPercentage = 5, // never below 5%
MaxSamplingPercentage = 100 // never above 100%
};
// Fixed-rate sampling – fixed rate
// var fixedSampling = new SamplingTelemetryProcessor(config)
// {
// SamplingPercentage = 25 // keeps 25% of items
// };
});
| Sampling Type | Advantage | Use Case |
|---|---|---|
| Adaptive | Adjusts automatically | Variable traffic |
| Fixed-rate | Predictable and consistent rate | Precise statistical analysis |
| Ingestion | Configured on the Application Insights side, no redeployment | Cost reduction without code changes |
Module 5 – Distributed Tracing and Correlation
Fundamental Concepts
flowchart TD
Browser -->|HTTP GET /order/42| API[API Gateway]
API -->|HTTP POST /validate| VS[Validation Service]
API -->|HTTP POST /payment| PS[Payment Service]
PS -->|SQL Query| DB["(SQL Database)"]
subgraph W3C TraceContext Headers
H1["traceparent: 00-{traceId}-{spanId}-01"]
H2["tracestate: vendor-specific data"]
end
| Concept | Description |
|---|---|
| TraceId | Unique GUID identifying the entire end-to-end transaction |
| SpanId | GUID identifying a single operation within the trace |
| Activity | .NET representation of a span (System.Diagnostics.Activity) |
| ActivitySource | Factory for creating named Activities |
| W3C TraceContext | HTTP standard for propagating correlation IDs |
ActivitySource (.NET) – Manual Instrumentation
using System.Diagnostics;
// Define the source at the class / assembly level
public static class Telemetry
{
public static readonly ActivitySource Source =
new ActivitySource("MyApp.OrderProcessing", "1.0.0");
}
public class OrderProcessor
{
public async Task ProcessAsync(Order order)
{
// Creates a span (Activity) – automatic parent context propagation
using var activity = Telemetry.Source.StartActivity("ProcessOrder");
activity?.SetTag("order.id", order.Id);
activity?.SetTag("order.amount", order.TotalAmount);
activity?.SetTag("customer.id", order.CustomerId);
try
{
await ValidateAsync(order);
await ChargeAsync(order);
activity?.SetStatus(ActivityStatusCode.Ok);
}
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
activity?.RecordException(ex);
throw;
}
}
}
Registering the ActivitySource with OpenTelemetry
// Program.cs
builder.Services.AddOpenTelemetry()
.UseAzureMonitor()
.WithTracing(tracing =>
{
tracing
.AddSource("MyApp.OrderProcessing") // custom source
.AddAspNetCoreInstrumentation() // inbound HTTP
.AddHttpClientInstrumentation() // outbound HTTP
.AddSqlClientInstrumentation(); // SQL
})
.WithMetrics(metrics =>
{
metrics
.AddAspNetCoreInstrumentation()
.AddRuntimeInstrumentation();
});
W3C TraceContext – Cross-Service Propagation
// The SDK automatically injects headers for HttpClient calls
// Header: traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
// ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^
// version traceId (128-bit hex) parentId (64-bit) flags
// To read the IDs in the current context:
var traceId = Activity.Current?.TraceId.ToString();
var spanId = Activity.Current?.SpanId.ToString();
var parentId = Activity.Current?.ParentId;
_logger.LogInformation(
"Processing order {OrderId} | trace={TraceId} span={SpanId}",
orderId, traceId, spanId);
KQL Query – End-to-End Correlation
// Find all operations related to a TraceId
let targetTrace = "4bf92f3577b34da6a3ce929d0e0e4736";
union requests, dependencies, exceptions, traces
| where operation_Id == targetTrace
| project timestamp, itemType, name, duration, success, message
| order by timestamp asc
Transaction Map (End-to-End Transaction)
In Application Insights → Transaction Search → select a request → View all telemetry:
- Chronological view of all spans in the transaction.
- See nested dependencies, their duration, and status.
- Identify which service added latency.
Module 6 – Live Metrics Stream
Live Metrics Architecture
flowchart LR
App[Production Application] -->|QuickPulse SDK\nHTTPS polling| QP[QuickPulse Endpoint]
QP -->|WebSocket| Portal[Azure Portal\nLive Metrics]
Portal --> Engineer[Engineer]
- Display latency: ~1 second (near real-time).
- Data is not persisted in Log Analytics (display only).
- Enabled via
EnableQuickPulseMetricStream = truein configuration.
Metrics Available in Real Time
| Category | Metrics |
|---|---|
| Requests | Rate (req/s), average duration, failure rate |
| Dependencies | Call rate, duration, failure rate |
| Exceptions | Exceptions rate/s |
| Performance | Process CPU (%), memory (MB) |
| Event stream | Requests, traces, dependencies, exceptions live |
Real-Time Filtering (Custom Dimensions)
The right panel in Live Metrics shows the raw telemetry stream. You can filter by:
- Operation name (e.g.,
GET /api/orders) - Context properties (
cloud_RoleName,cloud_RoleInstance) - Result (success / failure)
// Properties added via TelemetryContext appear in Live Metrics
_telemetry.Context.Cloud.RoleName = "order-api";
_telemetry.Context.Cloud.RoleInstance = Environment.MachineName;
Typical Use Cases
- Validate a deployment: immediately observe whether the error rate rises after a deployment.
- Production debugging: track specific requests in real time without impacting stored logs.
- Demonstrations: show live behavior during a presentation.
Exam tip: Live Metrics stores no data in Log Analytics. Data is ephemeral.
Module 7 – Log Analytics Workspace and KQL
Workspace Architecture
flowchart TD
subgraph Sources
AI[Application Insights]
AS[App Service Logs]
AKS[AKS Logs]
AL[Activity Log]
VM[VM Diagnostics]
end
subgraph Log Analytics Workspace
T1[requests]
T2[exceptions]
T3[dependencies]
T4[traces]
T5[customEvents]
T6[customMetrics]
T7[AzureActivity]
T8[ContainerLog]
end
AI --> T1 & T2 & T3 & T4 & T5 & T6
AL --> T7
AKS --> T8
AS --> T4
VM --> T4
KQL – Essential Operators for AZ-204
where – Filter rows
requests
| where timestamp > ago(1h)
| where success == false
| where resultCode == "500"
project – Select columns
exceptions
| where timestamp > ago(24h)
| project timestamp, type, outerMessage, operation_Id, cloud_RoleName
extend – Add calculated columns
requests
| where timestamp > ago(1h)
| extend DurationSec = duration / 1000.0
| extend IsSlow = DurationSec > 2.0
| project timestamp, name, DurationSec, IsSlow
summarize – Aggregate data
// Error rates by operation over the last 24h
requests
| where timestamp > ago(24h)
| summarize
TotalRequests = count(),
FailedRequests = countif(success == false),
AvgDuration = avg(duration),
P95Duration = percentile(duration, 95)
by name
| extend ErrorRate = round(100.0 * FailedRequests / TotalRequests, 2)
| order by ErrorRate desc
join – Join tables
// Join requests with their exceptions for analysis
requests
| where timestamp > ago(1h) and success == false
| join kind=leftouter (
exceptions
| where timestamp > ago(1h)
| project exceptionType = type, exceptionMsg = outerMessage, operation_Id
) on operation_Id
| project timestamp, name, resultCode, exceptionType, exceptionMsg
bin + summarize – Time series
// Error rates per 5-minute interval
requests
| where timestamp > ago(6h)
| summarize
Total = count(),
Errors = countif(success == false)
by bin(timestamp, 5m)
| extend ErrorRate = 100.0 * Errors / Total
| render timechart
Useful KQL Queries for the Exam
// 1 – Top 10 slowest operations
requests
| where timestamp > ago(24h)
| summarize P99 = percentile(duration, 99) by name
| top 10 by P99 desc
// 2 – Exceptions by type over the last 7 days
exceptions
| where timestamp > ago(7d)
| summarize Count = count() by type
| order by Count desc
// 3 – Failed dependencies
dependencies
| where timestamp > ago(1h) and success == false
| project timestamp, name, target, resultCode, duration
| order by timestamp desc
// 4 – Traces by severity level
traces
| where timestamp > ago(1h)
| summarize Count = count() by severityLevel
// 0=Verbose, 1=Information, 2=Warning, 3=Error, 4=Critical
// 5 – Request → exception correlation (by operation_Id)
let failedOps = requests
| where success == false and timestamp > ago(1h)
| project operation_Id, reqName = name;
exceptions
| where timestamp > ago(1h)
| join kind=inner failedOps on operation_Id
| project timestamp, reqName, type, outerMessage
Cross-workspace Queries
// Query multiple workspaces in a single query
union
workspace("workspace-prod").requests,
workspace("workspace-staging").requests
| where timestamp > ago(1h)
| summarize Count = count() by bin(timestamp, 5m), $__table
| render timechart
Log-Based Alerts (Log Alerts)
Key parameters when creating a Log alert:
- Evaluation frequency: every 5 min / 15 min / 1h.
- Time window: period over which the query is run.
- Threshold: e.g.,
> 0critical exceptions → triggers the alert. - Aggregation:
count,average,min,max.
Module 8 – Azure Monitor Alerts
Alert Architecture
flowchart TD
subgraph Signal Sources
M[Azure Monitor Metrics]
L[Log Analytics KQL]
A[Activity Log]
H[Azure Service Health]
end
subgraph Alert Rule
C[Condition\nStatic or dynamic threshold]
AG[Action Group]
end
subgraph Action Group Actions
E[Email / SMS]
W[Webhook]
AF[Azure Function]
LA[Logic App]
IT[ITSM Connector]
AR[Azure Runbook]
end
M & L & A & H --> C
C -->|Triggered| AG
AG --> E & W & AF & LA & IT & AR
Metric Alerts – Static vs. Dynamic Threshold
| Criterion | Static Threshold | Dynamic Threshold (ML) |
|---|---|---|
| Configuration | Fixed value defined manually | Calculated automatically by Machine Learning |
| Adaptability | No – same threshold 24/7 | Yes – adapts to seasonal patterns |
| Historical data | Not required | Requires at least 3 days |
| Use case | CPU > 90%, Errors > 100/min | Normal traffic on weekends vs. weekdays |
| Sensitivity | N/A | High / Medium / Low |
// Conceptual example of a static metric alert condition:
// Metric: requests/failed
// Operator: GreaterThan
// Threshold: 10
// Aggregation: Count
// Window: 5 minutes
// Frequency: 1 minute
Log Alerts (KQL-based)
// Rule: trigger an alert if more than 5 critical exceptions in 5 minutes
exceptions
| where timestamp > ago(5m)
| where severityLevel >= 3
| summarize CriticalErrors = count()
| where CriticalErrors > 5
Log alert rule parameters:
- Frequency: every 5 minutes.
- Lookback window: 5 minutes.
- Threshold:
Number of results > 0.
Activity Log Alerts
Triggered on events such as:
Microsoft.Web/sites/restart/action– App Service restartMicrosoft.KeyVault/vaults/delete– Key Vault deletionMicrosoft.Authorization/roleAssignments/write– RBAC modification
// Example of an Activity Log alert condition
{
"field": "operationName",
"equals": "Microsoft.Web/sites/restart/action"
}
Action Groups – Configuration
flowchart LR
AG["Action Group\n'ops-team-alerts'"] --> Email["📧 Email\nops@company.com"]
AG --> SMS["📱 SMS\n+1-555-000-0000"]
AG --> WH["🔗 Webhook\nhttps://teams.webhook.url"]
AG --> AF["⚡ Azure Function\nAlertProcessor"]
AG --> ITSM["🎫 ServiceNow\nITSM Connector"]
AG --> LA["🔄 Logic App\nAutoRemediation"]
Notification Throttling
- Alert suppression: avoids spam in case of repetitive alerts.
- Alert processing rules: suppress or modify notifications based on criteria (time window, resource tag).
- Maintenance window: scheduled notification suppression during a maintenance window.
# Create an Action Group via Azure CLI
az monitor action-group create \
--name "ops-team-alerts" \
--resource-group "rg-monitoring" \
--short-name "ops-alerts" \
--email-receiver name="ops-email" \
email-address="ops@company.com" \
use-common-alert-schema true
# Create a static metric alert
az monitor metrics alert create \
--name "high-error-rate" \
--resource-group "rg-monitoring" \
--scopes "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/sites/{app}" \
--condition "count requests/failed > 10" \
--window-size 5m \
--evaluation-frequency 1m \
--action "ops-team-alerts"
Module 9 – Application Map
Overview
The Application Map provides a topological view of all application components and their dependencies. It is built automatically from collected telemetry data.
graph LR
FE[Blazor Frontend\ncloud_RoleName=blazor-app] -->|HTTP| API[REST API\ncloud_RoleName=order-api]
API -->|SQL| DB["(Azure SQL)"]
API -->|HTTP| PAY[Payment Service\ncloud_RoleName=payment-svc]
API -->|AMQP| SB[Service Bus]
PAY -->|HTTP| EXT[Stripe API\nexternal]
style DB fill:#f0f0f0
style EXT fill:#ffe0e0
Information Displayed on Each Node
| Information | Description |
|---|---|
| Request count | Traffic volume to this component |
| Failure rate | % of failed requests (red circle if > threshold) |
| Average duration | Average latency of calls |
| Active alerts | Azure Monitor alerts linked to the component |
| Insights | Anomalies detected by Smart Detection |
Configuring Component Name (cloud_RoleName)
// Method 1: via TelemetryInitializer
public class RoleNameInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
telemetry.Context.Cloud.RoleName = "order-api";
telemetry.Context.Cloud.RoleInstance = Environment.MachineName;
}
}
// Method 2: via appsettings.json (OpenTelemetry)
// {
// "AzureMonitor": {
// "ServiceName": "order-api"
// }
// }
// Method 3: environment variable
// OTEL_SERVICE_NAME=order-api
Important: Without
cloud_RoleNameconfigured, all components appear under the same name on the map. This is the most common mistake when configuring a multi-service architecture.
Identifying Performance Hotspots
- Click on a node to see inbound/outbound operations.
- Click on an edge (arrow) to see dependency details.
- Red nodes indicate a high failure rate.
- Use the Time Range filter to compare before/after a deployment.
Module 10 – Availability Tests
Test Types
| Type | Status | Description |
|---|---|---|
| URL Ping Test | ⚠️ Deprecated (Sept. 2026) | Simple GET test on a URL |
| Multi-step Web Test | ⚠️ Deprecated | HTTP request sequence (.webtest) |
| Standard Test | ✅ Recommended | Configurable HTTP test with SSL validation |
| Custom TrackAvailability | ✅ Recommended | Run from your own code |
Standard Availability Test – Configuration
flowchart LR
subgraph Azure Availability Infrastructure
LOC1[East US]
LOC2[West Europe]
LOC3[Southeast Asia]
LOC4[Brazil South]
LOC5[Australia East]
end
LOC1 & LOC2 & LOC3 & LOC4 & LOC5 -->|HTTP GET/POST| App[https://myapp.azurewebsites.net/health]
App -->|200 OK + body match| Result[✅ Pass]
App -->|Timeout / 5xx / SSL invalid| Alert[🚨 Alert]
Standard Test configuration options:
- URL: endpoint to test.
- HTTP Verb: GET, POST, HEAD.
- Request headers: e.g.,
Authorization,Content-Type. - Request body: payload for POST tests.
- Parse dependent requests: load CSS, JS, images.
- SSL certificate check: validate the certificate is valid + X days.
- Frequency: every 5, 10, or 15 minutes.
- Locations: minimum 5 recommended to avoid false positives.
Response Validation
{
"successCriteria": {
"httpStatusCode": 200,
"contentMatch": "healthy",
"sslCertificateRemainingLifetimeDays": 7
}
}
Custom TrackAvailability – Custom Tests
// Azure Function or Worker Service running a custom test
public class CustomAvailabilityTest
{
private readonly TelemetryClient _telemetry;
private readonly HttpClient _httpClient;
public async Task RunTestAsync()
{
var testName = "Login Flow E2E Test";
var startTime = DateTimeOffset.UtcNow;
var timer = Stopwatch.StartNew();
bool passed = false;
string message = string.Empty;
try
{
// Simulate a complete login scenario
var loginResponse = await _httpClient.PostAsJsonAsync("/api/auth/login",
new { username = "testuser", password = "testpass" });
loginResponse.EnsureSuccessStatusCode();
var token = await loginResponse.Content.ReadFromJsonAsync<TokenResponse>();
// Verify the token is valid
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token!.AccessToken);
var profileResponse = await _httpClient.GetAsync("/api/users/me");
profileResponse.EnsureSuccessStatusCode();
passed = true;
message = "Login flow completed successfully";
}
catch (Exception ex)
{
message = ex.Message;
}
finally
{
timer.Stop();
_telemetry.TrackAvailability(
name: testName,
timeStamp: startTime,
duration: timer.Elapsed,
runLocation: "Custom-Azure-Function",
success: passed,
message: message);
}
}
}
Availability Alerts
Alerts are created automatically when creating an availability test with these default settings:
- Condition: failure from 2 or more locations out of 3 attempts.
- Sensitivity:
Medium. - Action: email to the test author.
Module 11 – Smart Detection
Overview
Smart Detection is a set of machine learning rules enabled by default in Application Insights, which continuously analyze telemetry data to detect anomalies.
flowchart LR
Telemetry[Continuous\ntelemetry stream] --> ML[ML Engine\nSmart Detection]
ML -->|Anomaly detected| Notification[Email / Alert Rule]
ML --> Rules
subgraph Rules
FA[Failure Anomalies]
PD[Performance Degradation]
DF[Dependency Failure]
MA[Memory Leak Detection]
SR[Slow Page Load]
end
Smart Detection Rules
| Rule | What it detects |
|---|---|
| Failure Anomalies | Abnormal increase in request failure rate |
| Performance Degradation | Abnormal increase in request or dependency duration |
| Dependency Failure | Abnormal degradation of a specific dependency |
| Slow Page Load | Abnormally slow page loading |
| Abnormal Rise in Exception Volume | Abnormal increase in exception volume |
| Memory Leak Detection | Upward trend in memory usage |
| Abnormal Rise in Daily Data Volume | Abnormally high volume of ingested data |
Configuring Smart Detection Alerts
In Application Insights → Smart Detection:
- Each rule can be enabled / disabled individually.
- Configure an Action Group to receive notifications.
- Set the sensitivity (High / Medium / Low) based on criticality.
# Disable a rule via Azure CLI
az monitor app-insights component update \
--app "my-app-insights" \
--resource-group "rg-monitoring" \
--query "properties.SmartDetectionEnabled"
# Update via ARM/Bicep
resource smartDetectionRule 'microsoft.insights/components/ProactiveDetectionConfigs@2018-05-01-preview' = {
name: '${appInsights.name}/slowpageloadtime'
properties: {
enabled: false
sendEmailsToSubscriptionOwners: false
}
}
Smart Detection vs. Classic Alerts
| Criterion | Smart Detection | Azure Monitor Alerts |
|---|---|---|
| Configuration | Automatic (ML) | Manual (defined threshold) |
| Threshold | Dynamic, based on history | Static or dynamic (separate ML) |
| Detection delay | Can take several minutes to hours | Configurable (1 min minimum) |
| Use case | Unexpected anomalies | Known SLA violations |
| Response | Email / Action Group | Full Action Group |
Exam tip: Smart Detection detects unknown anomalies; classic alerts detect known threshold violations.
Module 12 – Profiler and Snapshot Debugger
Application Insights Profiler
The Profiler collects code-level profiling traces to identify performance bottlenecks in production.
flowchart TD
App[Production application] -->|Periodic profiling\n~2 min every hour| P[Profiler Agent]
P -->|Upload traces| AI[Application Insights]
AI --> PT[Profiler Traces\nCall Tree View]
PT --> Hot[🔴 Hot Path\nLines consuming\nthe most CPU]
PT --> Cold[🟢 Cold Path\nRarely used lines]
Enabling the Profiler
# Via the Azure portal: Application Insights → Performance → Profiler → Enable
# Via App Service:
az webapp config appsettings set \
--name "my-api" \
--resource-group "rg-prod" \
--settings APPLICATIONINSIGHTS_PROFILER_ENABLED=true
// For .NET applications, the Profiler is enabled via the SDK
// appsettings.json
{
"ApplicationInsights": {
"ConnectionString": "...",
"EnableAdaptiveSampling": true,
"EnableProfiler": true
}
}
Analyzing a Profiler Call Tree
ProcessOrder [100%] 850ms
├── ValidateOrder [ 5%] 42ms
├── GetCustomer [12%] 102ms ← SQL dependency
├── CalculatePricing [71%] 603ms 🔴 HOT PATH
│ ├── GetRules [65%] 552ms ← slow external HTTP call
│ └── ApplyRules [ 6%] 51ms
└── SaveOrder [12%] 103ms ← SQL dependency
- Flames (🔴) indicate lines consuming the most CPU.
- Click a frame to see the exact source code.
- Compare multiple traces to validate if the issue is systematic.
Snapshot Debugger
The Snapshot Debugger automatically captures a snapshot of the application state (local variables, stack trace) at the moment an exception occurs.
sequenceDiagram
participant App as Application
participant SD as Snapshot Debugger Agent
participant AI as Application Insights
App->>App: Exception thrown
App->>SD: Exception intercepted
SD->>SD: Snapshot threshold reached?
SD->>App: In-process debugger attachment
App->>SD: Snapshot captured (mini-dump)
SD->>AI: Snapshot uploaded
AI->>Dev: Notification available
Dev->>AI: Open snapshot in VS / portal
Enabling the Snapshot Debugger
// NuGet package: Microsoft.ApplicationInsights.SnapshotCollector
// appsettings.json
{
"SnapshotCollectorConfiguration": {
"IsEnabled": true,
"IsEnabledInDeveloperMode": false,
"ThresholdForSnapshotting": 1, // snapshots from the 1st exception
"MaximumSnapshotsRequired": 3, // max 3 snapshots per exception
"MaximumCollectionPlanSize": 50,
"ReconstructScubaPayload": false
}
}
// Program.cs
builder.Services.AddSnapshotCollector(config =>
builder.Configuration.Bind(nameof(SnapshotCollectorConfiguration), config));
Manually Triggering a Snapshot
using Microsoft.ApplicationInsights.SnapshotCollector;
public class OrderService
{
private readonly ISnapshotCollector _snapshotCollector;
public async Task ProcessAsync(Order order)
{
try
{
await ProcessOrderInternalAsync(order);
}
catch (Exception ex)
{
// Explicitly request a snapshot for this exception
_snapshotCollector.RequestSnapshot(ex);
throw;
}
}
}
Viewing a Snapshot
- In Application Insights → Failures → select an exception.
- Click Open debug snapshot.
- View:
- Call stack at the time of the exception.
- Local variables at each stack frame.
- Method parameters in their exact state.
- Open in Visual Studio for a complete debugging experience.
Security: Snapshots may contain sensitive data (passwords, PII). Restrict access via RBAC. Enable the Snapshot Debugger Role for authorized users.
| Comparison | Profiler | Snapshot Debugger |
|---|---|---|
| Purpose | Identify performance bottlenecks | Debug exceptions in production |
| Data collected | CPU call tree (sampling) | Local variables + stack at exception time |
| Performance impact | Minimal (~2% overhead) | Minimal (triggered only on exception) |
| Retention | 30 days in App Insights | 15 days in App Insights |
| Activation | Portal / SDK / App Service settings | NuGet package + configuration |
Module 13 – AZ-204 Review Questions
Read each question, think about the answer, then consult the explanation.
Q1. Your application emits telemetry data to Application Insights. Which TelemetryClient method should you use to record the execution time of a call to an external Redis cache?
- A)
TrackRequest() - B)
TrackEvent() - C)
TrackDependency() - D)
TrackTrace()
Answer and explanation
C – TrackDependency()
TrackDependency() is designed to record outbound calls to external systems (databases, APIs, caches, etc.). TrackRequest() is reserved for inbound calls. TrackEvent() records business events. TrackTrace() records log messages.
Q2. You need to identify why a specific HTTP request takes 8 seconds to respond. Which Application Insights tool lets you visualize the Call Tree of code executed during that request?
- A) Live Metrics Stream
- B) Application Map
- C) Snapshot Debugger
- D) Application Insights Profiler
Answer and explanation
D – Application Insights Profiler
The Profiler collects CPU execution traces that let you visualize the Call Tree and identify the most time-consuming lines of code. The Snapshot Debugger captures state at exception time, not performance. The Application Map shows service topology.
Q3. You want all telemetry items emitted by your application to automatically include the TenantId field. What is the best approach?
- A) Add
TenantIdmanually to eachTrackEvent()call - B) Implement an
ITelemetryInitializer - C) Configure an
ITelemetryProcessor - D) Use a sampling filter
Answer and explanation
B – ITelemetryInitializer
An ITelemetryInitializer is called for every telemetry item before it is sent. This is the ideal pattern for enriching all items with common properties. An ITelemetryProcessor is used to filter or modify items (e.g., sampling).
Q4. Your team receives 50 alert emails per hour due to intermittent failures of a non-critical dependency. Which Azure Monitor feature allows reducing this notification volume without disabling the alert?
- A) Smart Detection
- B) Alert Processing Rules (suppression)
- C) Dynamic Thresholds
- D) Log Analytics Saved Queries
Answer and explanation
B – Alert Processing Rules
Alert Processing Rules allow suppressing notifications during a time window, redirecting them, or applying throttling rules without modifying the alert rule itself. Smart Detection is a separate anomaly detection system.
Q5. Which KQL query returns the number of failed requests per operation for the last 6 hours?
- A)
requests | where success == false | count by name - B)
requests | where timestamp > ago(6h) | summarize count() by name | where success == false - C)
requests | where timestamp > ago(6h) and success == false | summarize Count = count() by name - D)
requests | filter success = false | group by name | count
Answer and explanation
C
The correct KQL syntax uses summarize Count = count() by name for aggregation. Option A uses count by which is not valid KQL syntax. Option B filters after the summarize (too late). Option D uses incorrect SQL syntax (filter, group by).
Q6. Which HTTP header is used by the W3C TraceContext standard to propagate correlation IDs between services?
- A)
X-Request-Id - B)
X-Correlation-Id - C)
traceparent - D)
X-B3-TraceId
Answer and explanation
C – traceparent
The W3C TraceContext standard (RFC 7230) defines the traceparent header (and optionally tracestate) to propagate correlation information. X-Request-Id and X-Correlation-Id are proprietary conventions. X-B3-TraceId is used by the B3 format (Zipkin).
Q7. A Standard availability test detects that your SSL certificate expires in 3 days. How does Application Insights handle this situation?
- A) The test fails immediately with an SSL error code
- B) The test succeeds but generates a warning
- C) The test fails if the remaining lifetime is less than the configured value (
sslCertificateRemainingLifetimeDays) - D) Application Insights automatically renews the certificate
Answer and explanation
C
The Standard Test lets you configure an sslCertificateRemainingLifetimeDays threshold. If the certificate expires in fewer days than this threshold, the test fails, triggering an alert. Application Insights does not have the capability to renew certificates.
Q8. Your microservices architecture has 8 services. On the Application Map, several components appear grouped under a single node. Which context property must you configure to distinguish them?
- A)
telemetry.Context.Session.Id - B)
telemetry.Context.Cloud.RoleName - C)
telemetry.Context.Operation.Name - D)
telemetry.Context.User.Id
Answer and explanation
B – telemetry.Context.Cloud.RoleName
cloud_RoleName is the property used by Application Insights to distinguish components on the Application Map. Without this property, all services hosted on the same Azure resource appear merged. cloud_RoleInstance distinguishes instances of the same component.
Q9. Which of the following statements about Live Metrics Stream is correct?
- A) Live Metrics data is stored in Log Analytics and queryable via KQL
- B) Live Metrics requires a direct connection between the Azure portal and the application
- C) Live Metrics displays data with ~1 second latency but does not persist it in Log Analytics
- D) Live Metrics only works with autoinstrumentation
Answer and explanation
C
Live Metrics operates via the QuickPulse protocol with ~1 second latency. Data is ephemeral and not stored in Log Analytics. It works with the Application Insights SDK and OpenTelemetry. The connection goes through the quickpulse.applicationinsights.azure.com endpoint, not directly from the portal.
Q10. Which method is the correct approach for emitting a custom metric while minimizing the number of network calls to Application Insights?
- A)
_telemetry.TrackMetric("MyMetric", value)on each occurrence - B)
_telemetry.GetMetric("MyMetric").TrackValue(value)to pre-aggregate on the client side - C)
_logger.LogInformation("Metric: {Value}", value)and extract via KQL - D) Configure an
ITelemetryProcessorto aggregate metrics
Answer and explanation
B – GetMetric().TrackValue()
GetMetric() returns a Metric object that pre-aggregates values in memory (count, sum, min, max) and only sends a periodic summary to Application Insights (by default every 60 seconds), significantly reducing transmitted data volume and ingestion costs.
Q11. You want to create an alert that triggers when your API error rate exceeds twice the normal value based on the last 7 days, without defining a fixed threshold. Which alert type should you use?
- A) Log alert with KQL query
- B) Metric alert with static threshold
- C) Metric alert with Dynamic Thresholds
- D) Smart Detection Rule
Answer and explanation
C – Metric alert with Dynamic Thresholds
Dynamic Thresholds use ML to automatically calculate thresholds based on history (7, 14, or 21 days). They adapt to seasonal patterns. Smart Detection is automatic but not configurable according to specific criteria like “twice the normal”.
Q12. When creating a Standard Availability Test, which three configuration elements can you define for the request? (Choose 3)
- A) SSL certificate validation and minimum validity duration
- B) HTTP verb (GET, POST, HEAD)
- C) Request body
- D) Response validation rules
- E) Test timeout in milliseconds
Answer and explanation
A, B, C
For a Standard Test, you can configure:
- ✅ A: SSL validation with minimum validity duration
- ✅ B: HTTP verb (GET, POST, HEAD, etc.)
- ✅ C: request body (useful for POST tests)
- ❌ D: “Response validation rules” is not a named option – you can check the HTTP code and do a content match, but not via an option called that
- ❌ E: the timeout is not a freely configurable parameter in Standard Test
Summary – AZ-204 Monitoring Cheat Sheet
mindmap
root((AZ-204\nMonitoring))
Application Insights
SDK TelemetryClient
TrackEvent
TrackMetric / GetMetric
TrackException
TrackDependency
TrackRequest
OpenTelemetry Distro
Autoinstrumentation
Connection String
Observability
Logs → Log Analytics
Traces → W3C Correlation
Metrics → Azure Monitor
Tools
Live Metrics Stream
Application Map
Profiler
Snapshot Debugger
Availability Tests
Smart Detection
Alerts
Metric Alerts
Static
Dynamic Thresholds
Log Alerts KQL
Activity Log Alerts
Action Groups
Essential KQL
where
project
extend
summarize
join
bin + render
Quick Reference Table
| Scenario | Solution |
|---|---|
| Application goes down, don’t want to wait for users | Availability Test + Alert |
| Identify which line of code is slow | Application Insights Profiler |
| Debug an exception in production | Snapshot Debugger |
| See traffic in real time | Live Metrics Stream |
| Understand microservices topology | Application Map |
| Get alerted if error rate rises abnormally | Smart Detection / Dynamic Threshold Alert |
| Correlate logs from multiple services | operation_Id (W3C TraceContext) |
| Avoid alert spam | Alert Processing Rules (suppression) |
| Reduce metric ingestion costs | GetMetric() pre-aggregation / Sampling |
| Test from multiple regions worldwide | Standard Availability Test (5+ locations) |
Search Terms
az-204 · monitoring · troubleshooting · applications · azure · developer · microsoft · alerts · application · insights · log · architecture · snapshot · availability · configuration · custom · detection · kql · metrics · monitor · profiler · smart · analytics · debugger