Skip to content
Back to Blog
1 min read

Azure Log Analytics: Central Logging Platform

Log Analytics is the database I’ve spent the most hours in this year that nobody calls a database. It’s where every Azure diagnostic, AppInsights trace, Sentinel event, and custom log eventually lives, queryable in KQL. Two pieces of advice from experience: set the retention deliberately (the per-GB pricing is usually fine, the long retention isn’t), and learn enough KQL to write a summarize ... by bin(TimeGenerated, 5m) without thinking. That single query template has paid for itself a thousand times over.

Create Workspace

az monitor log-analytics workspace create \
    --workspace-name my-workspace \
    --resource-group myRG \
    --location eastus \
    --retention-time 90

Data Sources

SourceMethod
Azure ResourcesDiagnostic settings
VMsLog Analytics agent
ContainersContainer Insights
ApplicationsApplication Insights
CustomData Collector API

Enable Diagnostics

# Enable VM diagnostics
az monitor diagnostic-settings create \
    --name vm-diagnostics \
    --resource /subscriptions/.../virtualMachines/myVM \
    --logs '[{"category":"VMPerfCounters","enabled":true}]' \
    --metrics '[{"category":"AllMetrics","enabled":true}]' \
    --workspace /subscriptions/.../workspaces/my-workspace

KQL Queries

Basic Queries

// Search across all tables
search "error"
| take 100

// Query specific table
Heartbeat
| where TimeGenerated > ago(1h)
| summarize count() by Computer

Performance Analysis

// CPU usage by VM
Perf
| where ObjectName == "Processor" and CounterName == "% Processor Time"
| where InstanceName == "_Total"
| summarize AvgCPU = avg(CounterValue), MaxCPU = max(CounterValue) by Computer, bin(TimeGenerated, 5m)
| render timechart

// Memory usage
Perf
| where ObjectName == "Memory" and CounterName == "% Used Memory"
| summarize AvgMemory = avg(CounterValue) by Computer, bin(TimeGenerated, 5m)
| render timechart

Security Analysis

// Failed sign-ins
SigninLogs
| where ResultType != 0
| summarize FailedAttempts = count() by UserPrincipalName, IPAddress
| where FailedAttempts > 5
| order by FailedAttempts desc

// Unusual sign-in locations
SigninLogs
| where ResultType == 0
| summarize Locations = dcount(Location) by UserPrincipalName
| where Locations > 3

Application Logs

// Exceptions by type
exceptions
| summarize count() by type
| order by count_ desc

// Slow requests
requests
| where duration > 1000
| project timestamp, name, duration, resultCode
| order by duration desc

Saved Queries

# Save query as function
az monitor log-analytics workspace saved-search create \
    --workspace-name my-workspace \
    --resource-group myRG \
    --name HighCPU \
    --category "Performance" \
    --display-name "High CPU VMs" \
    --query "Perf | where ObjectName == 'Processor' | where CounterValue > 90"

Alerts

# Create log alert
az monitor scheduled-query create \
    --name high-cpu-alert \
    --resource-group myRG \
    --scopes /subscriptions/.../workspaces/my-workspace \
    --condition "count > 5" \
    --condition-query "Perf | where CounterName == '% Processor Time' | where CounterValue > 90" \
    --action-groups /subscriptions/.../actionGroups/ops-team \
    --evaluation-frequency 5m \
    --window-size 15m \
    --severity 2

Data Collection Rules

az monitor data-collection rule create \
    --name my-dcr \
    --resource-group myRG \
    --location eastus \
    --data-flows '[{
        "streams": ["Microsoft-Perf"],
        "destinations": ["my-workspace"]
    }]' \
    --data-sources '{
        "performanceCounters": [{
            "name": "perfCounters",
            "streams": ["Microsoft-Perf"],
            "samplingFrequencyInSeconds": 60,
            "counterSpecifiers": [
                "\\Processor(_Total)\\% Processor Time",
                "\\Memory\\Available Bytes"
            ]
        }]
    }'

Export Data

# Export to storage
az monitor log-analytics workspace data-export create \
    --workspace-name my-workspace \
    --resource-group myRG \
    --name export-to-storage \
    --destination /subscriptions/.../storageAccounts/mystorageaccount \
    --table-names Heartbeat Perf

Log Analytics: insights from all your data.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.