Skip to content
Last9
Book demo

Azure Monitor Metrics

Send Azure Monitor metrics to Last9 using OTel Collector.

Send all Azure Monitor metrics to Last9 using the OpenTelemetry Collector’s azuremonitorreceiver. The collector polls the Azure Monitor REST API directly — no Event Hubs, no Diagnostic Settings changes, no extra Azure infrastructure.

How it works

Azure Monitor REST API
│ polls every 5 min
OTel Collector (azuremonitorreceiver)
+ azureauthextension (service principal)
│ OTLP/gRPC + gzip
Last9

The collector scrapes all metrics for resources in your configured subscription and resource groups. It requires only a service principal with the Monitoring Reader role — a read-only credential scoped to monitoring data.

Prerequisites

  • Azure subscription with resources emitting metrics
  • Azure CLI installed
  • Docker or a Kubernetes cluster (AKS)
  • Last9 OTLP endpoint and authorization header (from Settings > Integrations > OTLP)

Step 1 — Create a Service Principal

az ad sp create-for-rbac \
--name "last9-monitor-reader" \
--role "Monitoring Reader" \
--scopes "/subscriptions/<SUBSCRIPTION_ID>"

Save the output — you need appId (CLIENT_ID), password (CLIENT_SECRET), and tenant (TENANT_ID).

Step 2 — Configure the Collector

Create collector-config.yaml:

extensions:
health_check:
endpoint: 0.0.0.0:13133
azureauth:
service_principal:
tenant_id: ${env:AZURE_TENANT_ID}
client_id: ${env:AZURE_CLIENT_ID}
client_secret: ${env:AZURE_CLIENT_SECRET}
receivers:
azuremonitor:
subscription_ids:
- ${env:AZURE_SUBSCRIPTION_ID}
resource_groups:
- ${env:AZURE_RESOURCE_GROUP}
collection_interval: 300s
initial_delay: 1s
cloud: AzureCloud
auth:
authenticator: azureauth
processors:
memory_limiter:
check_interval: 1s
limit_mib: 256
spike_limit_mib: 64
resource:
attributes:
- key: cloud.provider
value: azure
action: upsert
- key: cloud.platform
value: azure_monitor
action: upsert
- key: cloud.account.id
value: ${env:AZURE_SUBSCRIPTION_ID}
action: upsert
batch:
timeout: 10s
send_batch_size: 100
send_batch_max_size: 200
exporters:
otlp_grpc/last9:
endpoint: ${env:LAST9_OTLP_ENDPOINT}
headers:
Authorization: ${env:LAST9_OTLP_HEADER}
compression: gzip
timeout: 30s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
service:
extensions: [health_check, azureauth]
pipelines:
metrics:
receivers: [azuremonitor]
processors: [memory_limiter, resource, batch]
exporters: [otlp_grpc/last9]
telemetry:
logs:
level: info

Step 3 — Set Environment Variables

Create a .env file (do not commit):

AZURE_TENANT_ID=<your-tenant-id>
AZURE_SUBSCRIPTION_ID=<your-subscription-id>
AZURE_CLIENT_ID=<service-principal-app-id>
AZURE_CLIENT_SECRET=<service-principal-password>
AZURE_RESOURCE_GROUP=<resource-group-to-monitor>
LAST9_OTLP_ENDPOINT=<otlp-endpoint> # e.g. otlp-aps1.last9.io:443
LAST9_OTLP_HEADER=<authorization-header>

Step 4 — Run

Docker:

docker run --rm \
--env-file .env \
-v $(pwd)/collector-config.yaml:/etc/otelcol-contrib/config.yaml \
otel/opentelemetry-collector-contrib:latest

AKS (Kubernetes):

# Create secret
kubectl create secret generic last9-azure-monitor \
--from-literal=AZURE_TENANT_ID="..." \
--from-literal=AZURE_SUBSCRIPTION_ID="..." \
--from-literal=AZURE_CLIENT_ID="..." \
--from-literal=AZURE_CLIENT_SECRET="..." \
--from-literal=AZURE_RESOURCE_GROUP="..." \
--from-literal=LAST9_OTLP_ENDPOINT="..." \
--from-literal=LAST9_OTLP_HEADER="..."
apiVersion: apps/v1
kind: Deployment
metadata:
name: otelcol-azure-monitor
spec:
replicas: 1
selector:
matchLabels:
app: otelcol-azure-monitor
template:
metadata:
labels:
app: otelcol-azure-monitor
spec:
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:latest
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 300Mi
envFrom:
- secretRef:
name: last9-azure-monitor
volumeMounts:
- name: config
mountPath: /etc/otelcol-contrib/config.yaml
subPath: config.yaml
volumes:
- name: config
configMap:
name: otelcol-azure-monitor

Tuning

ParameterDefaultGuidance
collection_interval300sAzure Monitor refreshes most metrics every 1–5 min; lowering below 60s rarely adds value
resource_groupsallAlways scope to specific groups to avoid hitting Azure Monitor API rate limits
servicesallAdd a services: filter to limit to specific Microsoft.* resource types
memory_limiter.limit_mib256Increase to 512+ for subscriptions with 1000+ resources

Metrics naming

Metrics arrive in Last9 following the pattern:

azure_<resource_type>_<metric_name>

Examples:

  • azure_microsoft_containerapp_apps_requests
  • azure_microsoft_compute_virtualmachines_percentage_cpu
  • azure_microsoft_sql_servers_databases_dtu_consumption_percent

Every metric includes resource attributes for filtering:

AttributeExample
cloud.providerazure
cloud.platformazure_monitor
cloud.account.id77514676-...
resource.id/subscriptions/.../resourceGroups/...
resource.groupmy-resource-group
resource.regioneastus

Querying metrics

Once metrics are flowing, open app.last9.io/metrics to browse and query your Azure Monitor metrics using PromQL.