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 ▼ Last9The 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: infoStep 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:443LAST9_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:latestAKS (Kubernetes):
# Create secretkubectl 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/v1kind: Deploymentmetadata: name: otelcol-azure-monitorspec: 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-monitorTuning
| Parameter | Default | Guidance |
|---|---|---|
collection_interval | 300s | Azure Monitor refreshes most metrics every 1–5 min; lowering below 60s rarely adds value |
resource_groups | all | Always scope to specific groups to avoid hitting Azure Monitor API rate limits |
services | all | Add a services: filter to limit to specific Microsoft.* resource types |
memory_limiter.limit_mib | 256 | Increase 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_requestsazure_microsoft_compute_virtualmachines_percentage_cpuazure_microsoft_sql_servers_databases_dtu_consumption_percent
Every metric includes resource attributes for filtering:
| Attribute | Example |
|---|---|
cloud.provider | azure |
cloud.platform | azure_monitor |
cloud.account.id | 77514676-... |
resource.id | /subscriptions/.../resourceGroups/... |
resource.group | my-resource-group |
resource.region | eastus |
Querying metrics
Once metrics are flowing, open app.last9.io/metrics to browse and query your Azure Monitor metrics using PromQL.