Lab 01: Log Analytics Workspace Setup
This lab builds the shared data platform for the rest of the tutorial sequence. You will create a Log Analytics workspace, configure retention and daily cap settings, and connect Azure resources so telemetry lands in one searchable location.
| Attribute | Value |
| Difficulty | Beginner |
| Estimated Duration | 35-45 minutes |
| Azure Monitor Tier | Foundational |
| Primary Services | Log Analytics workspace, diagnostic settings, Azure Monitor Agent |
| Skills Practiced | Workspace creation, retention design, resource connection, validation |
Prerequisites
- Azure CLI installed and authenticated with
az login. - Contributor access to a sandbox subscription.
- Permission to create resource groups, workspaces, virtual machines, storage accounts, and diagnostic settings.
- Familiarity with Azure resource IDs and the Azure portal.
- Bash-compatible shell for environment variables.
Define reusable variables:
export LOCATION="koreacentral"
export RG="rg-monitoring-lab01"
export WORKSPACE_NAME="lawmonlab01"
export STORAGE_NAME="stmonlab01001"
export VM_NAME="vmmonlab01"
export DCR_NAME="dcr-monlab01"
Architecture Diagram
flowchart TD
VM[Azure VM] --> AMA[Azure Monitor Agent]
AMA --> DCR[Data Collection Rule]
App[Storage account diagnostics] --> DS1[Diagnostic setting]
SA[Storage account] --> DS1
DCR --> LAW[Log Analytics workspace]
DS1 --> LAW
LAW --> Query[KQL queries]
LAW --> Alert[Alert rules]
LAW --> Workbook[Workbooks]
Lab Objectives
By the end of the lab, you will have:
- A dedicated resource group for monitoring experiments.
- A Log Analytics workspace with retention and daily cap configured.
- A storage account streaming logs and metrics into the workspace.
- A VM connected through Azure Monitor Agent and a data collection rule.
- A validation query proving that data is arriving.
Step-by-Step Instructions
Step 1: Create the resource group
az group create \
--name "$RG" \
--location "$LOCATION" \
--output json
| Command | Purpose |
az group create | Create a resource group. |
--name | Name of the resource. |
--location | Azure region for the resource. |
--output | Output format for the result. |
Expected result:
{
"location": "koreacentral",
"name": "rg-monitoring-lab01",
"properties": {
"provisioningState": "Succeeded"
}
}
Step 2: Create the Log Analytics workspace
az monitor log-analytics workspace create \
--resource-group "$RG" \
--workspace-name "$WORKSPACE_NAME" \
--location "$LOCATION" \
--sku "PerGB2018" \
--retention-time 30 \
--output json
| Command | Purpose |
az monitor log-analytics workspace create | Create a Log Analytics workspace. |
--resource-group | Resource group that contains the resource. |
--workspace-name | Name of the Log Analytics workspace. |
--location | Azure region for the resource. |
--sku | SKU tier of the resource. |
--retention-time | Data retention period in days. |
--output | Output format for the result. |
Review the workspace properties:
az monitor log-analytics workspace show \
--resource-group "$RG" \
--workspace-name "$WORKSPACE_NAME" \
--query "{name:name,location:location,retentionInDays:retentionInDays,workspaceId:customerId}" \
--output json
| Command | Purpose |
az monitor log-analytics workspace show | Show a Log Analytics workspace. |
--resource-group | Resource group that contains the resource. |
--workspace-name | Name of the Log Analytics workspace. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Step 3: Set a daily cap for predictable spend
az monitor log-analytics workspace update \
--resource-group "$RG" \
--workspace-name "$WORKSPACE_NAME" \
--set workspaceCapping.dailyQuotaGb=2 \
--output json
| Command | Purpose |
az monitor log-analytics workspace update | Update a Log Analytics workspace. |
--resource-group | Resource group that contains the resource. |
--workspace-name | Name of the Log Analytics workspace. |
--set | Property assignment applied during update. |
--output | Output format for the result. |
Why this matters:
- Retention protects investigation depth.
- Daily cap protects your sandbox budget.
- Both settings should be explicit rather than relying on defaults.
az storage account create \
--name "$STORAGE_NAME" \
--resource-group "$RG" \
--location "$LOCATION" \
--sku "Standard_LRS" \
--kind "StorageV2" \
--output json
| Command | Purpose |
az storage account create | Create a storage account. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--location | Azure region for the resource. |
--sku | SKU tier of the resource. |
--kind | Resource kind. |
--output | Output format for the result. |
Capture IDs for later steps:
export WORKSPACE_ID=$(az monitor log-analytics workspace show \
--resource-group "$RG" \
--workspace-name "$WORKSPACE_NAME" \
--query "id" \
--output tsv)
export STORAGE_ID=$(az storage account show \
--name "$STORAGE_NAME" \
--resource-group "$RG" \
--query "id" \
--output tsv)
| Command | Purpose |
az monitor log-analytics workspace show | Show a Log Analytics workspace. |
--resource-group | Resource group that contains the resource. |
--workspace-name | Name of the Log Analytics workspace. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
az storage account show | Show properties of a storage account. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Step 5: Connect storage logs and metrics to the workspace
az monitor diagnostic-settings create \
--name "send-to-law" \
--resource "$STORAGE_ID" \
--workspace "$WORKSPACE_ID" \
--logs '[{"categoryGroup":"audit","enabled":true}]' \
--metrics '[{"category":"Transaction","enabled":true}]' \
--output json
| Command | Purpose |
az monitor diagnostic-settings create | Create a diagnostic setting. |
--name | Name of the resource. |
--resource | Target resource ID or name for the operation. |
--workspace | Log Analytics workspace name or resource ID that receives the logs. |
--logs | Log categories or settings to collect. |
--metrics | Metric categories to collect. |
--output | Output format for the result. |
List the diagnostic settings to confirm the attachment:
az monitor diagnostic-settings list \
--resource "$STORAGE_ID" \
--output json
| Command | Purpose |
az monitor diagnostic-settings list | List diagnostic settings for a resource. |
--resource | Target resource ID or name for the operation. |
--output | Output format for the result. |
Step 6: Create a VM to generate heartbeat telemetry
az vm create \
--resource-group "$RG" \
--name "$VM_NAME" \
--image "Ubuntu2204" \
--admin-username "azureuser" \
--generate-ssh-keys \
--size "Standard_B2s" \
--public-ip-sku "Standard" \
--output json
| Command | Purpose |
az vm create | Create a virtual machine. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
--image | VM image used to create the virtual machine. |
--admin-username | Administrator username for the virtual machine. |
--generate-ssh-keys | Generates SSH keys for the virtual machine if missing. |
--size | Virtual machine size (SKU). |
--public-ip-sku | SKU for the public IP address. |
--output | Output format for the result. |
Capture the VM resource ID:
export VM_ID=$(az vm show \
--resource-group "$RG" \
--name "$VM_NAME" \
--query "id" \
--output tsv)
| Command | Purpose |
az vm show | Show properties of a virtual machine. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
az monitor data-collection rule create \
--name "$DCR_NAME" \
--resource-group "$RG" \
--location "$LOCATION" \
--data-flows streams="[\"Microsoft-Perf\"]" destinations="[\"la-workspace\"]" \
--destinations log-analytics name="la-workspace" workspace-resource-id="$WORKSPACE_ID" \
--data-sources performance-counters name="perfCounters" streams="[\"Microsoft-Perf\"]" sampling-frequency="PT1M" counter-specifiers="[\"\\Processor(_Total)\\% Processor Time\",\"\\Memory\\Available MBytes\"]" \
--output json
| Command | Purpose |
az monitor data-collection rule create | Create a data collection rule. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--location | Azure region for the resource. |
--data-flows | Data flow mappings from sources to destinations. |
--destinations | Destinations that receive collected data. |
--data-sources | Data sources collected by the rule. |
--output | Output format for the result. |
Step 8: Install Azure Monitor Agent on the VM
az vm extension set \
--resource-group "$RG" \
--vm-name "$VM_NAME" \
--name "AzureMonitorLinuxAgent" \
--publisher "Microsoft.Azure.Monitor" \
--enable-auto-upgrade true \
--output json
| Command | Purpose |
az vm extension set | Install or update a virtual machine extension. |
--resource-group | Resource group that contains the resource. |
--vm-name | Name of the virtual machine. |
--name | Name of the resource. |
--publisher | Publisher of the VM extension. |
--enable-auto-upgrade | Enables automatic extension upgrades. |
--output | Output format for the result. |
Associate the VM with the data collection rule:
export DCR_ID=$(az monitor data-collection rule show \
--name "$DCR_NAME" \
--resource-group "$RG" \
--query "id" \
--output tsv)
az monitor data-collection rule association create \
--name "vm-law-association" \
--resource "$VM_ID" \
--rule-id "$DCR_ID" \
--output json
| Command | Purpose |
az monitor data-collection rule show | Show a data collection rule. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
az monitor data-collection rule association create | Associate a data collection rule with a resource. |
--name | Name of the resource. |
--resource | Target resource ID or name for the operation. |
--rule-id | Resource ID of the data collection rule to associate. |
--output | Output format for the result. |
Step 9: Wait for telemetry ingestion and run validation queries
It may take several minutes before the first records appear.
az monitor log-analytics query \
--workspace "$WORKSPACE_ID" \
--analytics-query "Heartbeat | where TimeGenerated > ago(30m) | summarize Computers=dcount(Computer)" \
--output table
| Command | Purpose |
az monitor log-analytics query | Run a KQL query against a Log Analytics workspace. |
--workspace | Log Analytics workspace ID for the query. |
--analytics-query | Kusto (KQL) query to execute. |
--output | Output format for the result. |
Run a second query for metrics and logs from the storage account:
az monitor log-analytics query \
--workspace "$WORKSPACE_ID" \
--analytics-query "AzureMetrics | where TimeGenerated > ago(30m) | summarize Records=count() by ResourceProvider" \
--output table
| Command | Purpose |
az monitor log-analytics query | Run a KQL query against a Log Analytics workspace. |
--workspace | Log Analytics workspace ID for the query. |
--analytics-query | Kusto (KQL) query to execute. |
--output | Output format for the result. |
Validation Steps
Use these checks to verify success:
- Confirm workspace configuration.
az monitor log-analytics workspace show \
--resource-group "$RG" \
--workspace-name "$WORKSPACE_NAME" \
--query "{retentionInDays:retentionInDays,dailyQuotaGb:workspaceCapping.dailyQuotaGb,publicNetworkAccessForIngestion:publicNetworkAccessForIngestion}" \
--output json
| Command | Purpose |
az monitor log-analytics workspace show | Show a Log Analytics workspace. |
--resource-group | Resource group that contains the resource. |
--workspace-name | Name of the Log Analytics workspace. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
- Confirm the VM association exists.
az monitor data-collection rule association list \
--resource "$VM_ID" \
--output table
| Command | Purpose |
az monitor data-collection rule association list | List data collection rule associations. |
--resource | Target resource ID or name for the operation. |
--output | Output format for the result. |
- Confirm diagnostic settings are attached to the storage account.
az monitor diagnostic-settings list \
--resource "$STORAGE_ID" \
--query "[].{name:name,workspaceId:workspaceId}" \
--output table
| Command | Purpose |
az monitor diagnostic-settings list | List diagnostic settings for a resource. |
--resource | Target resource ID or name for the operation. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
- Confirm the workspace receives telemetry.
az monitor log-analytics query \
--workspace "$WORKSPACE_ID" \
--analytics-query "union isfuzzy=true Heartbeat, Perf, AzureMetrics | where TimeGenerated > ago(30m) | summarize Records=count() by Type" \
--output table
| Command | Purpose |
az monitor log-analytics query | Run a KQL query against a Log Analytics workspace. |
--workspace | Log Analytics workspace ID for the query. |
--analytics-query | Kusto (KQL) query to execute. |
--output | Output format for the result. |
Validation is successful when the workspace exists, retention and quota settings are visible, the DCR association is present, and at least one telemetry table returns recent rows.
Cleanup Instructions
If you are continuing with later labs, keep the workspace and resource group. Otherwise delete the sandbox:
az group delete \
--name "$RG" \
--yes \
--no-wait
| Command | Purpose |
az group delete | Delete a resource group. |
--name | Name of the resource. |
--yes | Skips the confirmation prompt. |
--no-wait | Returns without waiting for the operation to finish. |
Optional partial cleanup if you want to keep the workspace but remove the VM:
az vm delete \
--resource-group "$RG" \
--name "$VM_NAME" \
--yes
| Command | Purpose |
az vm delete | Delete a virtual machine. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
--yes | Skips the confirmation prompt. |
See Also
Sources