Azure Monitor & Application Insights
Key Points
- Azure Monitor umbrella covers logs (Log Analytics), metrics, alerts. Application Insights = APM layer for .NET apps.
- Modern integration: Azure Monitor OpenTelemetry Distro — OTel-based, replaces classic ApplicationInsights SDK. Auto-instruments ASP.NET, HttpClient, EF, SQL, Service Bus.
- KQL (Kusto Query Language) for log queries. SQL-ish; very powerful.
- Live Metrics stream — real-time view of running app.
- Alerts: metric, log, activity log. Action groups for notifications (email, Teams, webhook, Logic App).
Concepts (deep dive)
What Azure Monitor and Application Insights are
These names confuse everyone, and the relationship matters: Azure Monitor is the umbrella platform — the place every Azure resource sends its telemetry — and Application Insights is one specific feature inside it, focused on application-level APM (requests, dependencies, traces, exceptions for your .NET app code). They share storage (Log Analytics workspaces), share query language (KQL), share alerting, and increasingly share an ingestion path (OpenTelemetry).
┌────────────────────────────────────────────────────────────────┐
│ Azure Monitor │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Metrics platform │ │ Logs (Log │ │
│ │ (time-series) │ │ Analytics │ │
│ │ │ │ workspace) │ │
│ │ dashboards │ │ │ │
│ │ alerts │ │ KQL queries │ │
│ └──────────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌─────────────────────────────┴─────────────────────────┐ │
│ │ Application Insights │ │
│ │ (APM for your app) │ │
│ │ │ │
│ │ requests, dependencies, traces, exceptions, │ │
│ │ customMetrics, Live Metrics stream │ │
│ │ ▲ │ │
│ │ │ ingested via OpenTelemetry (modern) or │ │
│ │ │ ApplicationInsights SDK (legacy) │ │
│ └───┼───────────────────────────────────────────────────┘ │
│ │ │
│ │ │
│ .NET app │
└────────────────────────────────────────────────────────────────┘
The mental model: telemetry from resources (VMs, App Service plans, AKS clusters, the platform itself) flows into Azure Monitor as platform metrics + activity logs; telemetry from your code (HTTP requests, SQL calls, custom events) flows into Application Insights via OpenTelemetry. Both end up in the same workspace, queryable side-by-side in KQL — which is how a senior engineer correlates "the app's p99 spiked at 10:32" with "the VMSS scale event happened at 10:31."
From the classic SDK to OpenTelemetry
Application Insights had its own .NET SDK for years (Microsoft.ApplicationInsights.AspNetCore). The modern path is the Azure Monitor OpenTelemetry Distro — a thin layer over the standard OpenTelemetry SDK that configures the right exporter and the right semantic conventions for App Insights. You write OTel code; the distro ships it to Azure. Same telemetry shows up; same KQL queries work; but your code is now portable to any OTel backend (Jaeger, Honeycomb, Grafana Tempo) by swapping the exporter. For new code in 2026: OTel distro, not the classic SDK.
Setup with OTel distro
builder.Services.AddOpenTelemetry()
.UseAzureMonitor(o => o.ConnectionString = "InstrumentationKey=...");
One line; auto-instruments traces, metrics, logs. Sends to Application Insights via OTLP.
Connection string
Replaces the older InstrumentationKey alone. Connection string supports regional endpoints.
KQL basics
Kusto Query Language is the query language of Azure Monitor / Log Analytics / App Insights. It reads like a Unix pipe — start with a table, push it through filters, joins, aggregations, and visualizations. Learn three commands (where, summarize, join) and you can answer ~80% of operational questions. KQL is also what every alert and dashboard is built on, so understanding it is the difference between "I have observability" and "I have a dashboard nobody can read."
requests
| where timestamp > ago(1h)
| where success == false
| summarize count() by resultCode, bin(timestamp, 5m)
| render timechart
// p95 latency by endpoint
requests
| summarize percentiles(duration, 95, 99) by name
| order by percentile_duration_99 desc
// Slow queries with related traces
dependencies
| where type == "SQL" and duration > 1000
| join (traces) on operation_Id
Tables in App Insights
| Table | Content |
|---|---|
requests | Incoming HTTP requests |
dependencies | Outgoing calls (HTTP, DB, custom) |
traces | Logs |
exceptions | Errors |
customEvents | App-defined |
customMetrics | App-defined metrics |
availabilityResults | Synthetic monitoring |
performanceCounters | OS/CLR counters |
Live Metrics
Real-time view: incoming/outgoing per-second, failures, dependencies. Browser dashboard updates ~1s.
Alerts
Three types: - Metric alerts: scalar thresholds (CPU > 80%). - Log alerts: KQL query results trigger. - Activity Log alerts: ARM events.
resource alert 'Microsoft.Insights/scheduledQueryRules@2023-12-01' = {
name: 'high-failure-rate'
properties: {
severity: 2
enabled: true
evaluationFrequency: 'PT5M'
windowSize: 'PT5M'
criteria: {
allOf: [{
query: 'requests | where success == false | count'
operator: 'GreaterThan'
threshold: 100
}]
}
actions: { actionGroups: [actionGroupId] }
}
}
Action groups
- SMS
- Voice
- Webhook
- Azure Function / Logic App
- ITSM connector
Workspaces
Modern: workspace-based App Insights. Logs land in shared workspace; cross-resource queries.
Sampling
Reduces ingestion cost. Errors usually always sampled.
Adaptive sampling: dynamically reduces under load.
Correlation
W3C TraceContext. Activity flows across services. AppInsights joins by operation_Id.
Dashboards & Workbooks
- Dashboards: pinned tiles; Azure Portal.
- Workbooks: rich, parameterized reports. KQL + visualizations.
Custom metrics & events
private static readonly Meter _meter = new("MyApp.Orders");
private static readonly Counter<long> _placed = _meter.CreateCounter<long>("orders.placed");
_placed.Add(1, new TagList { { "type", "online" } });
OTel meters automatically flow to App Insights.
Distributed tracing
Auto with OTel. Click a request → see all dependencies in tree:
GET /orders 250ms
├─ SQL Server (orders) 30ms
├─ HTTP GET /products 180ms
│ └─ SQL Server 120ms
└─ Service Bus publish 20ms
Diagnostic settings
resource diag 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
scope: cosmosDb
properties: {
logs: [{ category: 'DataPlaneRequests', enabled: true }]
workspaceId: laWorkspaceId
}
}
Stream Azure resource logs (Cosmos, Key Vault, Storage) to Log Analytics. KQL on top.
Cost management
- Sampling reduces ingestion.
- Daily cap on workspace.
- Retention tier (interactive 30-90 days; archive cheaper).
Migration from classic SDK
Old:
New:
Migrate for: vendor-neutral; cross-platform; better OTel ecosystem.
Synthetic monitoring (availability tests)
Periodic HTTP pings from global locations. Multi-step transaction tests. Alerts on failure.
Code: correct vs wrong
❌ Wrong: classic SDK in new app
✅ Correct: OTel distro
❌ Wrong: no sampling at high volume
Cost spike on traffic burst.
✅ Correct: adaptive sampling
OTel distro applies it by default.
Design patterns for this topic
Pattern 1 — "OTel distro for new apps"
- Intent: vendor-neutral; modern.
Pattern 2 — "Workspace-based App Insights"
- Intent: cross-resource KQL.
Pattern 3 — "Sampling for cost"
- Intent: scale ingestion.
Pattern 4 — "Workbooks for dashboards"
- Intent: parameterized rich reports.
Pattern 5 — "Diagnostic settings to Log Analytics"
- Intent: unified observability across Azure.
Pros & cons / trade-offs
| Aspect | Pros | Cons |
|---|---|---|
| Azure Monitor | All Azure native | Azure-coupled |
| App Insights | Rich .NET APM | Cost at scale |
| KQL | Powerful queries | Learning curve |
| Adaptive sampling | Cost control | Some loss |
When to use / when to avoid
- Use for Azure-native apps.
- Use OTel distro for new apps.
- Avoid classic SDK in greenfield.
- Avoid unbounded ingestion — sample.
Interview Q&A
Q1. Azure Monitor vs App Insights? Azure Monitor is the umbrella (logs/metrics/alerts/diagnostics). App Insights is the APM layer.
Q2. Modern .NET App Insights setup? AddOpenTelemetry().UseAzureMonitor(). OTel distro replaces classic SDK.
Q3. KQL? Kusto Query Language. SQL-ish but more powerful for time-series logs.
Q4. Live Metrics? Real-time per-second telemetry stream from running app.
Q5. Sampling? Reduce ingestion. Adaptive scales with load. Errors usually preserved.
Q6. Workbooks? Parameterized rich reports with KQL + visualization.
Q7. Tables in App Insights? requests, dependencies, traces, exceptions, customMetrics, availabilityResults.
Q8. Diagnostic settings? Stream Azure resource logs into Log Analytics. KQL across.
Q9. Alert types? Metric, log, activity log.
Q10. Cost optimization? Sampling, daily cap, archive tier, exclude noisy categories.
Q11. Synthetic monitoring? Periodic HTTP pings; multi-step tests. Availability monitoring.
Q12. Cross-resource queries? Workspace-based App Insights enables cross-resource KQL.
Gotchas / common mistakes
- ⚠️ Classic SDK in new code.
- ⚠️ No sampling — runaway ingestion.
- ⚠️ High-cardinality custom metrics — series explosion.
- ⚠️ No alerts — outages unnoticed.
- ⚠️ Default 90-day retention — costly; tune.