Monitor Diagnostic Setting
Overview
The monitor_diagnostic_setting module wires Azure resources to one or more diagnostic destinations (Log Analytics Workspace, Storage Account, Event Hub, or a partner solution) so their platform logs and metrics flow into a queryable store. It is intentionally a low-level module: with one exception, it is not configured directly in tfvars. Instead, each supported resource type exposes a diagnostic_settings map on its own input variable, and the module projects those per-resource maps into the diagnostic setting resources. The exception is the subscription-scope Activity Log export, which has no parent resource entry and uses the dedicated subscription_diagnostic_setting root variable (see Subscription Activity Log).
This keeps the user-facing configuration close to the resource being monitored (the diagnostic settings live on the vault entry, the storage account entry, and so on), while a single module creates the actual azurerm_monitor_diagnostic_setting resources.
Each entry in diagnostic_settings produces a separate azurerm_monitor_diagnostic_setting resource, so a single Azure resource can have multiple settings — for example, one routing logs to a workspace and another routing them to a storage account for long-term retention.
Module Structure
| Module | Azure Resource | Purpose |
|---|---|---|
monitor_diagnostic_setting |
azurerm_monitor_diagnostic_setting |
Routes platform logs/metrics for a target resource to one or more destinations |
log_analytics_workspace |
azurerm_log_analytics_workspace |
Workspace destination, referenced by key — see Log Analytics Workspace |
storage_account |
azurerm_storage_account |
Storage destination, referenced by key |
Supported Resource Types
The following root variables accept a diagnostic_settings map on each entry.
| Root Variable | Module | Composite Key Prefix | Log Categories |
|---|---|---|---|
recovery_services_vault |
recovery_services_vault |
recovery_services_vault.<vault_key>.<setting_key> |
CoreAzureBackup, AddonAzureBackupAlerts, AddonAzureBackupJobs, AddonAzureBackupPolicy, AddonAzureBackupProtectedInstance, AddonAzureBackupStorage |
key_vault |
key_vault |
key_vault.<vault_key>.<setting_key> |
AuditEvent, AzurePolicyEvaluationDetails |
automation_account |
automation_account |
automation_account.<account_key>.<setting_key> |
JobLogs, JobStreams, DscNodeStatus, AuditEvent |
firewall |
firewall |
firewall.<firewall_key>.<setting_key> |
AZFWApplicationRule, AZFWNetworkRule, AZFWNatRule, AZFWThreatIntel, AZFWDnsQuery, AZFWFqdnResolveFailure — see Firewall |
application_gateway |
application_gateway |
application_gateway.<agw_key>.<setting_key> |
ApplicationGatewayAccessLog, ApplicationGatewayPerformanceLog, ApplicationGatewayFirewallLog — see Application Gateway |
network_security_group |
network_security_group |
network_security_group.<nsg_key>.<setting_key> |
NetworkSecurityGroupEvent, NetworkSecurityGroupRuleCounter |
public_ip |
public_ip |
public_ip.<public_ip_key>.<setting_key> |
DDoSProtectionNotifications, DDoSMitigationFlowLogs, DDoSMitigationReports |
bastion_host |
bastion_host |
bastion_host.<bastion_key>.<setting_key> |
BastionAuditLogs |
virtual_network_gateway |
virtual_network_gateway |
virtual_network_gateway.<gateway_key>.<setting_key> |
GatewayDiagnosticLog, TunnelDiagnosticLog, RouteDiagnosticLog, IKEDiagnosticLog, P2SDiagnosticLog — see Virtual Network Gateway |
storage_account |
storage_account |
storage_account.<account_key>.<setting_key> |
Transaction (account level); StorageRead, StorageWrite, StorageDelete (per service, set service; see Storage Account Sub-Resource) |
mssql_server (databases) |
mssql_database |
mssql_database.<server_key>.<database_key>.<setting_key> |
SQLInsights, AutomaticTuning, QueryStoreRuntimeStatistics, Errors, DatabaseWaitStatistics, Timeouts, Blocks, Deadlocks, DevOpsOperationsAudit, SQLSecurityAuditEvents — see Azure SQL Database and SQL Database Composite Key |
subscription_diagnostic_setting |
— (subscription scope) | subscription.current.<setting_key> |
Activity Log: Administrative, Security, ServiceHealth, Alert, Recommendation, Policy, Autoscale, ResourceHealth — see Subscription Activity Log |
The log category names above are representative; the authoritative per-resource list is the Azure Monitor supported categories table or az monitor diagnostic-settings categories list.
When additional resource types are wired through this module, they will be added to this table. See Adding Diagnostic Settings to a New Resource Type for the procedure.
How the Module Resolves Each Type
The module declares all supported types in a single supported_resource_types map in src/modules/monitor_diagnostic_setting/locals.tf. Each entry pairs the resource's tfvars map (var_*) with its module output (mod_*) and declares two per-type behavior flags:
supports_destination_typeisfalsefornetwork_security_group,public_ip,virtual_network_gateway, andsubscription— Azure rejectslog_analytics_destination_type = "Dedicated"on them (they have no resource-specific tables, so it would re-apply forever), and the generic loop forces the argument tonull.has_service_suffixistrueonly forstorage_account— its settings can target a service sub-resource via the per-settingservicefield (see Storage Account Sub-Resource). The generic loop only readsdiag.servicewhen this flag is set.
Types whose targets aren't keyed by a top-level tfvars map key synthesize their module/resources pair inside the map instead of using a dedicated loop:
mssql_databasepre-flattens each server'sdatabasesmap into composite"<server>.<database>"keys (see SQL Database Composite Key).subscriptionwraps the subscription-scope settings in a single dummycurrententry (see Subscription Activity Log).mssql_serverdoesn't consume a user-supplieddiagnostic_settingsmap at all — for each server with log monitoring enabled on itsextended_auditing_policy, it synthesizes oneauditsetting targeting the server'smasterdatabase, keyedmssql_server.<server_key>.audit(see Azure SQL Database).
A single flatten (diagnostic_settings_flat) walks the map and feeds the resource block — there are no dedicated per-type loops — so adding a type requires only one new map entry plus the matching var_* / mod_* inputs.
How It Is Wired
The root file src/main.monitor_diagnostic_setting.tf only passes inputs into the module — it contains no transform logic. Each supported type contributes a var_* (its tfvars map) and a mod_* (its module output) pair:
Note: The var_* input name is the module's generic label, not always the root variable name. For example var_application_gateway = var.agws and var_network_security_group = var.nsgs — the module input stays singular and descriptive while the root variable keeps its own name.
The projection from each resource's diagnostic_settings map into the shape azurerm_monitor_diagnostic_setting expects lives inside the module at src/modules/monitor_diagnostic_setting/locals.tf. A single generic flatten walks every entry in supported_resource_types, producing a list whose elements key as "<resource_type>.<resource_key>.<setting_key>", then a single resource block iterates the list:
The triple-segment key (<resource_type>.<resource_key>.<setting_key>) keeps diagnostic setting keys unique across resource types and across multiple settings on the same target resource. SQL databases extend this to a four-segment key — see SQL Database Composite Key.
Storage Account Sub-Resource
Storage account diagnostics can target either the account itself or one of its service sub-resources. The Transaction metric lives on the account ID; the per-service logs (StorageRead, StorageWrite, StorageDelete) live on the blob, file, queue, or table service sub-resource. The service field on each diagnostic_settings entry selects the target. When unset it targets the account itself (metrics only); set it to blob, file, queue, or table to target that service. Log categories require service to be set, because the account level exposes no resource logs (this is enforced by a variable validation).
storage_account is the only type flagged has_service_suffix = true in supported_resource_types, which makes the generic flatten map service to the /<service>Services/default suffix on the resolved account ID — so service = "file" targets <account_id>/fileServices/default, while omitting service targets <account_id>. Use one diagnostic setting per service when you need logs from more than one:
SQL Database Composite Key
Azure SQL databases are nested under logical servers (one databases map per mssql_server entry), and the mssql_database module is keyed by the composite "<server>.<database>" key. The generic flatten keys resources by a single map key, so the mssql_database entry in supported_resource_types pre-flattens each server's databases map into a composite-keyed map before the generic loop sees it:
Because the composite key already contains a dot, the generic key expands to the four-segment mssql_database.<server_key>.<database_key>.<setting_key>, and the matching default name is mssql_database-<server_key>.<database_key>-<setting_key> (the server/database separator stays a dot). Diagnostics are declared on the database entry, not the server:
This produces a diagnostic setting keyed mssql_database.epic.clarity.audit. The full server/database configuration lives in Azure SQL Database; only the diagnostic part is shown here.
This module is wired with var_mssql_server = var.mssql_server (to read the nested databases/diagnostic_settings maps) and mod_mssql_database = module.mssql_database.mssql_database (to resolve database IDs by composite key).
Subscription Activity Log
Subscription-scope diagnostic settings export the Activity Log (control-plane events: resource writes/deletes, service health, policy evaluations) to the same destinations as resource diagnostics. Unlike every other supported type, there is no parent resource entry to attach a diagnostic_settings map to — the settings are configured directly in the root subscription_diagnostic_setting variable, and the target is the subscription itself (/subscriptions/<subscription_id>).
Inside the module, the subscription entry in supported_resource_types synthesizes the missing resource level with a single dummy current entry:
Settings therefore key as subscription.current.<setting_key> with the default name subscription-current-<setting_key>. The Activity Log has no resource-specific tables, so log_analytics_destination_type does not apply (the variable schema omits the field and the module forces it to null), and only log categories are valid — the Activity Log exposes no metrics or category groups:
This produces one azurerm_monitor_diagnostic_setting keyed subscription.current.activitylog targeting the subscription. The module is wired with var_subscription_diagnostic_setting = var.subscription_diagnostic_setting and var_subscription_id = var.subscription_id (the same subscription ID the azurerm provider uses).
Adding Diagnostic Settings to a New Resource Type
Use this procedure to wire diagnostic settings into a module that does not yet support them. The goal is that an operator can opt into diagnostics by adding a diagnostic_settings map to a single entry in tfvars — no other wiring required.
1. Add the diagnostic_settings Map to the Root Variable
In src/variables.<resource>.tf, add a diagnostic_settings field to the object. Use this exact shape so every resource type stays consistent:
diagnostic_settings = optional(map(object({
name = optional(string)
workspace = optional(string)
log_analytics_destination_type = optional(string)
storage_account = optional(string)
eventhub_authorization_rule_id = optional(string)
eventhub_name = optional(string)
partner_solution_id = optional(string)
enabled_logs = optional(object({
categories = optional(list(string), [])
category_groups = optional(list(string), [])
}), {})
enabled_metrics = optional(list(string))
})), {})
2. Pass the New Resource Into the Module
In src/main.monitor_diagnostic_setting.tf, add a var_* input for the new resource's tfvars map and a mod_* input for its module output:
module "monitor_diagnostic_setting" {
source = "./modules/monitor_diagnostic_setting"
var_recovery_services_vault = var.recovery_services_vault
mod_recovery_services_vault = module.recovery_services_vault.recovery_services_vault
var_<root_variable> = var.<root_variable> # <- new
mod_<resource_module> = module.<resource_module>.<resource_output> # <- new
mod_log_analytics_workspace = module.log_analytics_workspace.log_analytics_workspace
mod_storage_account = module.storage_account.resource
}
3. Declare the New Inputs Inside the Module
In src/modules/monitor_diagnostic_setting/variables.tf, add matching declarations. var_* inputs hold tfvars maps; mod_* inputs receive module outputs and must be type = any:
4. Project Entries Into the Diagnostic-Setting Shape
In src/modules/monitor_diagnostic_setting/locals.tf, add an entry to the supported_resource_types map; the single flatten then picks it up automatically and keys each entry as "<resource_type>.<resource_key>.<setting_key>". Set the two behavior flags on the entry: supports_destination_type = false if Azure rejects log_analytics_destination_type on the resource type, and has_service_suffix = true only if the type targets service sub-resources the way storage accounts do. If the type isn't keyed by a top-level tfvars map key — or its settings aren't user-supplied at all — synthesize the module/resources pair inside the entry; the mssql_database, subscription, and mssql_server (audit) entries show the existing patterns.
5. Document the Resource Type
Add a row to the Supported Resource Types table above, including the valid log category names for that Azure resource. The authoritative list is the Azure Monitor supported categories table, or run:
Per-Entry Diagnostic Setting Block
This is the shape consumed on supported resource entries. At least one destination must be set — either workspace, storage_account, eventhub_authorization_rule_id, or partner_solution_id.
| Field | Type | Description | Default |
|---|---|---|---|
name |
string | Override the diagnostic setting name | "<resource_type>-<resource_key>-<setting_key>" |
workspace |
string | log_analytics_workspace key (workspace destination) |
null |
log_analytics_destination_type |
string | "Dedicated" (resource-specific tables) or "AzureDiagnostics" (legacy single table). Leave unset for the resource default. Not available on network_security_group, public_ip, virtual_network_gateway, or subscription_diagnostic_setting (Azure rejects Dedicated there). |
null |
storage_account |
string | storage_account key (storage destination for archive/retention) |
null |
eventhub_authorization_rule_id |
string | Full Event Hub namespace authorization rule ID. Pair with eventhub_name. |
null |
eventhub_name |
string | Event Hub name within the namespace referenced by eventhub_authorization_rule_id |
null |
partner_solution_id |
string | Full resource ID of a partner monitoring solution destination | null |
enabled_logs |
object | Log categories and category groups to enable (see below) | {} |
enabled_metrics |
list(string) | Metric category names to enable | null |
enabled_logs
| Field | Type | Description | Default |
|---|---|---|---|
categories |
list(string) | Individual log category names to enable | [] |
category_groups |
list(string) | Category groups to enable (e.g. "audit", "allLogs") |
[] |
Note: For a given setting, categories and category_groups are mutually exclusive — pick one approach. Available category names and groups are resource-specific.
Note: A single diagnostic setting can fan out to multiple destination types simultaneously (workspace + storage + event hub on one setting). To send to two workspaces or two storage accounts, define two separate entries in diagnostic_settings.
Tip: Prefer log_analytics_destination_type = "Dedicated" on new workspaces. It writes logs to per-resource tables (for example AddonAzureBackupJobs) instead of the legacy single AzureDiagnostics table, which keeps queries simpler and aligns with current Azure guidance.
Example: Recovery Vault With Multiple Settings
The full vault configuration lives in Backup. The diagnostic part of the entry can define multiple settings — for example, one to a workspace and another to a storage account for long-term retention:
recovery_services_vault = {
epic = {
resource_group = "recoveryvault"
storage_mode_type = "GeoRedundant"
diagnostic_settings = {
law = {
workspace = "shared"
log_analytics_destination_type = "Dedicated"
enabled_logs = {
categories = [
"CoreAzureBackup",
"AddonAzureBackupAlerts",
"AddonAzureBackupJobs",
"AddonAzureBackupPolicy",
"AddonAzureBackupProtectedInstance",
"AddonAzureBackupStorage",
]
}
}
archive = {
storage_account = "auditarchive"
enabled_logs = {
category_groups = ["allLogs"]
}
}
}
}
}
This produces two azurerm_monitor_diagnostic_setting resources keyed recovery_services_vault.epic.law and recovery_services_vault.epic.archive.
Naming Convention
monitor_diagnostic_setting does not use name_prefixes / name_suffixes. The name comes from the setting entry's name, or defaults to "<resource_type>-<resource_key>-<setting_key>" (for example recovery_services_vault-epic-law). The resource-type prefix is included in the default so two resources of different types that share a key (e.g. a vault and a key vault both named epic) don't produce duplicate diagnostic setting names. For composite-keyed types the resource-key segment keeps its internal dot (mssql_database-epic.clarity-audit), and subscription-scope settings use the dummy resource key (subscription-current-activitylog).