If your operations team measures success by whether servers are "up," you're measuring the wrong thing. Users don't care if your VM is running — they care whether they can log in, submit orders, and get responses in under two seconds.
On June 11, 2026, Azure Monitor made two capabilities generally available that make this shift practical: Service Level Indicators (SLIs) and Metrics Export. Together they close an observability gap that has been forcing enterprises to bolt on third-party platforms just to run SLO-driven operations natively.
This article is a practical guide: what these features actually do, how to implement them with real code (Azure CLI, Bicep, Terraform, Python, bash), and the pitfalls I'd warn you about before you start.
The Problem: Infrastructure Metrics Don't Tell You What Matters
Azure Monitor has always been good at infrastructure metrics. CPU usage, disk I/O, network throughput, memory pressure — all available out of the box for every Azure resource. But these are supply-side metrics. They tell you what your infrastructure is doing, not what your users are experiencing.
Consider a scenario I've seen play out in production more than once: your VMs show 40% CPU utilization (healthy), your database responds in 10ms (excellent), and network latency is 2ms (perfect). Meanwhile, users are reporting the application feels slow and broken.
The infrastructure metrics are fine. The user experience is not. Something in the middle — application logic, session handling, client-side rendering, a downstream dependency — is degrading the experience, and infrastructure metrics alone can't see it.
SRE teams have known this since Google's SRE book defined SLIs and SLOs as the foundation of reliable service delivery back in 2016. But implementing them in Azure historically meant either custom code (Application Insights custom metrics, hand-built Log Analytics queries) or third-party platforms (Datadog, New Relic, Dynatrace).
The native Azure Monitor SLI capability removes that excuse.
What Azure Monitor SLIs Actually Do
Defining what matters
An SLI is a quantitative measure of your service's behavior from the user's perspective. In Azure Monitor's GA implementation, you define an SLI through a handful of building blocks:
- Service group — the application or workload boundary the SLI represents.
- SLI type — whether you measure availability or latency.
- Evaluation method — whether Azure Monitor evaluates individual requests or time windows.
- Baseline target — the SLO the measured result is compared against.
Common SLIs you'll define this way:
- Availability: What percentage of requests complete successfully?
- Latency: What percentage of requests complete within 200ms?
- Error rate: What percentage of requests return errors?
The SLI runs continuously against incoming telemetry and produces a running score you can track over time — not a one-off dashboard query someone has to remember to run.
Setting targets (SLOs)
An SLO is the target you set for your SLI: "99.9% of requests complete within 200ms over a rolling 30-day window." In Azure Monitor you set the baseline target percentage and the evaluation period, and the platform computes compliance for you.
The most important derived number is the error budget — how much unreliability you're allowed. For a 99.9% SLO over 30 days, your error budget is roughly 43 minutes of bad behavior. That converts an abstract reliability target into a concrete number the whole team can work with: "We have 31 minutes of error budget left this month."
Alerting on burn rate, not thresholds
The most powerful feature is burn-rate alerting. Instead of alerting when a metric crosses a static threshold (CPU > 90%), you alert when your error budget is being consumed faster than sustainable.
Azure Monitor SLIs support three alert types you wire to action groups:
- Baseline alert — fires when the SLI falls below target over the evaluation period.
- Fast burn rate — detects rapid error budget consumption over a short lookback, e.g. 14.4x the sustainable rate over the last hour. At 14.4x, a 30-day error budget is gone in about two days. This is your page-the-on-call signal.
- Slow burn rate — detects sustained, slower consumption that will still miss the SLO if nothing changes. This is your create-a-ticket signal.
This multi-window approach, straight from Google's SRE workbook, dramatically reduces alert noise while catching real reliability issues early. You stop waking people up for transient CPU spikes and start waking them up only when users are actually about to be impacted.
What Metrics Export Does
Metrics Export solves the second half of the problem: getting Azure Monitor metrics out of Azure Monitor and into whatever platform your organization actually uses.
Before this, exporting metrics meant Log Analytics queries, custom connectors, or accepting multi-minute delays. Now you can stream platform metrics to:
- Azure Event Hubs — for custom processing pipelines and external systems (Datadog, Splunk, your own data lake).
- Azure Storage accounts — for long retention, archiving, and data-lake pipelines.
- Log Analytics — for query-driven analysis alongside logs.
Two mechanisms matter, and choosing the wrong one is a common mistake:
- Diagnostic settings — the classic per-resource export. Simple, but multi-dimensional metrics get flattened into single-dimensional aggregates.
- Data collection rule (DCR) based metric export — supports multi-dimensional metrics intact. If you need per-queue, per-endpoint, or per-instance breakdowns downstream, this is the one.
The native Prometheus/Grafana stack
Combine SLIs + Metrics Export + Azure Monitor workspace + Managed Grafana and you get a complete open-source-style observability stack running natively in Azure:
Azure resources ──► Azure Monitor (SLIs + SLOs + burn-rate alerts)
│
├── Metrics Export (DCR → Event Hubs / Log Analytics / Storage)
│
└── Managed Prometheus collection ──► Azure Monitor workspace
(Prometheus-compatible)
│
▼
Managed Grafana — dashboards + alerting
Enterprise governance of Azure Monitor, flexibility and ecosystem of Prometheus/Grafana, no third-party license, and no telemetry leaving your tenant.
Practical Implementation
Here's the implementation path I'd follow for a production web API.
Step 1: Define the SLI and SLO
In the portal: Azure Monitor → Service Level Indicators → create a service group for your application, add an availability SLI evaluated per request, set baseline target 99.9% over a rolling 30-day window, and enable fast/slow burn-rate alerts against your on-call action group.
Under the hood, an availability SLI over Application Insights data is computing something like this — worth knowing because you can sanity-check your SLI's numbers with the equivalent Log Analytics query:
requests
| where timestamp > ago(30d)
| summarize
total = count(),
good = countif(success == true and duration < 2000)
| extend availability_pct = round(100.0 * good / total, 3)
If your SLI score and this query disagree materially, your SLI's evaluation method or scope is misconfigured — fix that before you trust alerts.
Step 2: Export metrics via Azure CLI
Quick export of an App Service's platform metrics to Event Hubs:
SUB_ID="00000000-0000-0000-0000-000000000000"
az monitor diagnostic-settings create \
--name "orders-api-metrics-export" \
--resource "/subscriptions/$SUB_ID/resourceGroups/rg-prod/providers/Microsoft.Web/sites/orders-api" \
--metrics '[{"category":"AllMetrics","enabled":true}]' \
--event-hub "insights-metrics-prod" \
--event-hub-rule "/subscriptions/$SUB_ID/resourceGroups/rg-observability/providers/Microsoft.EventHub/namespaces/eh-observability-prod/authorizationrules/CaptureSender"
And a quick bash check of raw request metrics while you wait for the pipeline to warm up:
az monitor metrics list \
--resource "/subscriptions/$SUB_ID/resourceGroups/rg-prod/providers/Microsoft.Web/sites/orders-api" \
--metric "Http5xxx" "Requests" \
--interval PT1H \
--output json \
| jq -r '.value[] | .name.value as $m | .timeseries[0].data[] | "\($m)\t\(.timeStamp)\t\(.total)"' \
| tail -24
Step 3: Bicep — the full observability baseline
For repeatable deployments, define the Monitor workspace and the export in Bicep:
param location string = resourceGroup().location
// Azure Monitor workspace (Prometheus-compatible store for Managed Grafana)
resource amw 'Microsoft.Monitor/accounts@2023-04-03' = {
name: 'amw-prod-observability'
location: location
}
resource appService 'Microsoft.Web/sites@2024-04-01' existing = {
name: 'orders-api'
}
resource ehNamespace 'Microsoft.EventHub/namespaces@2024-01-01' existing = {
name: 'eh-observability-prod'
}
resource authRule 'Microsoft.EventHub/namespaces/authorizationRules@2024-01-01' existing = {
parent: ehNamespace
name: 'CaptureSender'
}
// Metrics export to Event Hubs
resource metricsExport 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
name: 'orders-api-metrics-export'
scope: appService
properties: {
eventHubAuthorizationRuleId: authRule.id
eventHubName: 'insights-metrics-prod'
metrics: [
{
category: 'AllMetrics'
enabled: true
}
]
}
}
Step 4: Terraform — same export, Terraform shops
If your estate is Terraform, the same export maps cleanly:
resource "azurerm_monitor_diagnostic_setting" "orders_api_metrics" {
name = "orders-api-metrics-export"
target_resource_id = azurerm_linux_web_app.orders_api.id
eventhub_name = azurerm_eventhub.metrics.name
eventhub_authorization_rule_id = azurerm_eventhub_namespace_authorization_rule.capture.id
metric {
category = "AllMetrics"
enabled = true
}
}
Check the azurerm provider changelog for native SLI/SLO resource support before you wire it into Terraform — until it lands there, define SLIs through the portal, ARM, or Bicep and keep them in a documented runbook.
Step 5: Python — consume the exported stream
Once metrics flow into Event Hubs, downstream processing is a small consumer. This one computes a rolling good/total ratio per metric — the raw material of an external SLO engine:
import json
from azure.eventhub import EventHubConsumerClient
CONN_STR = "<event-hub-connection-string>" # from Key Vault, never in code
def on_event(partition_ctx, event):
body = json.loads(event.body_as_str())
for record in body.get("records", []):
metric = record.get("properties", {})
name = record.get("metricName")
total = record.get("total")
print(f"{metric.get('resourceId')} {name} total={total}")
partition_ctx.update_checkpoint(event)
client = EventHubConsumerClient.from_connection_string(
conn_str=CONN_STR,
consumer_group="$Default",
eventhub_name="insights-metrics-prod",
)
with client:
client.receive(on_event=on_event, starting_position="-1")
From here you can push to Datadog, persist to a data lake for long retention, or feed your own compliance reporting.
Pitfalls to Avoid
- Flattened dimensions. Diagnostic settings export multi-dimensional metrics as single-dimensional aggregates — you'll lose per-queue, per-endpoint, per-instance breakdowns silently. If downstream tools need dimensions, use DCR-based metric export instead. Test this before you commit to a dashboard design.
- Event Hub firewall blocks. Diagnostic settings can't reach Event Hubs behind a virtual network firewall unless you enable the trusted Microsoft services bypass. The failure mode is a diagnostic setting that looks healthy but delivers nothing.
- Same-region requirement. For regional resources, the Event Hub must sit in the same region as the monitored resource. Multi-region estates need one hub per region or a hub in the right region per resource group.
- Setting SLO targets before you have baseline data. If you set 99.9% on day one with no idea what the service actually delivers, you'll either drown in burn-rate alerts or set a target so loose it's meaningless. Run the SLI for two to four weeks first, observe the real distribution, then set the target deliberately.
- One giant SLI for everything. An SLI scoped to an entire subscription tells you nothing actionable. Define one SLI per critical user journey — checkout, login, API search — so a burn-rate alert points at a specific service owner.
- Alert routing not split by burn speed. Fast burn should page a human; slow burn should open a ticket. Wiring both to the same notification channel recreates exactly the alert fatigue SLO alerting is supposed to kill.
What This Means for Enterprise Teams
Eliminating the third-party tax. Many enterprises pay $50–200K per year for Datadog or New Relic primarily for SLO tracking and cross-platform visibility. Native SLIs + Metrics Export + Managed Grafana credibly covers 80% of those use cases inside your existing Azure spend. Advanced code-level APM may still justify a specialist tool — but the SLO layer no longer does.
SRE adoption loses its tooling excuse. The hard part of adopting SRE was never the philosophy; it was building the platform. Azure now ships the platform.
Cross-team visibility. Metrics Export to Grafana means business stakeholders can see error budgets without Log Analytics access, and incident responders get burn-rate alerts that tell them exactly how urgent a situation really is.
Key Takeaways
- SLIs measure what users experience, not what servers do — the GA release shifts Azure Monitor from infrastructure dashboards to user-experience measurement with service groups, availability/latency SLI types, and request or time-window evaluation.
- Burn-rate alerting replaces threshold noise — baseline, fast-burn, and slow-burn alerts mapped to action groups give you the Google SRE workbook multi-window pattern natively.
- Metrics Export ends observability lock-in — stream metrics to Event Hubs, Azure Monitor workspace, or Log Analytics; just remember DCR export for multi-dimensional metrics.
- The native stack covers most enterprise needs — SLIs + Metrics Export + Managed Grafana can retire a large slice of third-party observability spend.
- Start with one critical user journey — run its SLI for a few weeks, set the SLO from real data, add burn-rate alerts, then expand. Don't instrument everything at once.
If your team is still running your Azure estate on CPU dashboards and "is it up?" checks, this GA release is the right moment to make the shift — the tooling finally exists, it's native, and the migration path is a few CLI commands away.