Skip to main content
emnode
Cost

Trim classic Storage Analytics log retention

Classic Storage Analytics logging writes request logs into a hidden $logs container on every account that has it switched on. With no retention policy, those logs accumulate forever and you pay to store them. Setting a sensible retention period lets Azure delete stale logs automatically and stops a silent line item growing on the bill.

12 min·10 sections·AZURE

Last reviewed

Classic log retention: the basics

Why do old storage logs quietly cost money?

Classic Storage Analytics logging is the older, account-level diagnostic feature that records read, write and delete requests for the Blob, Queue and Table services. When it is enabled, Azure writes one log entry per request into a hidden blob container named '$logs' inside the same storage account. On a busy account that is a steady stream of small log blobs, and they are charged at the account's normal blob storage rate, the same as any other data you keep.

The catch is the retention policy. Classic logging has an optional 'delete data' setting that tells Azure how many days of logs to keep. If that policy is not set, there is no automatic cleanup: Azure keeps every log blob indefinitely and it is left to you to delete them. Accounts that were created or configured before a retention policy was a habit often have logging on and retention off, so the '$logs' container has been growing for years without anyone looking at it. Because '$logs' is hidden from the normal portal container view, the growth is easy to miss entirely.

Azure Advisor surfaces this as the recommendation 'Revisit retention policy for classic log data in storage accounts' (Recommendation ID 386452d3-8df0-4174-94cb-fee063b3084f), under the Cost category. It is flagging accounts where classic log data is piling up so you can decide how long you genuinely need to keep it. The fix is to set a retention period that matches what you actually use, after which Azure deletes stale logs for you and the line item stops climbing.

In this lesson you will learn what classic Storage Analytics logging stores, why missing retention policies turn it into an ever-growing storage charge, how to find the accounts Advisor has flagged, and how to set a sensible retention period so Azure prunes stale logs for you. You will also see when to retire classic logging altogether in favour of Azure Monitor.

Fun fact

The container the portal will not show you

The '$logs' container that classic logging writes to is special: it is hidden from the standard container list in the Azure portal and from the storage browser. For classic storage accounts it only appears in tools like Azure Storage Explorer or through the storage APIs. That invisibility is exactly why these logs grow for years without anyone noticing. The data is sitting there being billed every month, but unless you go looking with the right tool, the portal acts as though the container is not there at all.

Finding accounts with unbounded classic logs

Priya runs the platform team at a company doing its annual cloud cost review. Azure Advisor's Cost tab lists several storage accounts under 'Revisit retention policy for classic log data in storage accounts'. She wants to see which accounts have classic logging on, and crucially which have no retention policy set, before changing anything.

Rather than open each account in the portal, where the '$logs' container is hidden anyway, she checks the logging settings directly so she can tell drift from deliberate configuration in one pass.

Show the classic logging settings for an account across all three services. A retention of 0 means logging is on but nothing is ever deleted.

$ az storage logging show --account-name logsheavyprod --services bqt -o table
Service Read Write Delete RetentionPolicy.Days
--------- ------ ------- -------- ---------------------
blob True True True 0
queue True True True 0
table False False False 0
# blob and queue log every request with NO retention: $logs grows forever.

Retention of 0 with logging on is the costly state: every request is logged and nothing is ever pruned. This is the account to fix first.

How classic logging accrues costdeep dive

Classic logging is a data-plane setting on the storage account, separate from the modern diagnostic settings that send data to Azure Monitor. For each of the Blob, Queue and Table services you can enable logging of read, write and delete operations independently, and each enabled operation writes log entries into the '$logs' container. The retention policy is a single property per service: 'RetentionPolicy.Days'. When it is unset or zero, Azure applies no automatic deletion and the logs stay until something removes them.

Those log blobs are ordinary block blobs in the account, so they are billed exactly like any other data at the account's storage tier and redundancy. There is no separate, cheaper rate for logs. The volume is driven by request rate: a chatty account servicing millions of operations a day generates far more log data than a quiet one, which is why the cost is so uneven across an estate and why the same recommendation can be trivial on one account and material on another.

Setting a retention period to a positive number of days tells Azure to delete log data older than that window on an ongoing basis. The cleanup is handled by the platform, not by you, so once a sensible value is set the container reaches a steady state where new logs arrive and old ones age out, and the stored volume, and therefore the charge, stops climbing. Microsoft's standing guidance is to prefer Azure Storage logs in Azure Monitor over classic Storage Analytics logging, so on accounts where the logs are not actively used the cleanest answer can be to retire classic logging entirely.

What is the impact of leaving retention unset?

The direct impact is a storage charge that only ever grows. With no retention policy, every logged request adds to the '$logs' container permanently, so an account that has been logging for years can be storing a large multiple of what anyone would ever read. Because the container is hidden from the normal portal view, the cost accrues silently and is rarely reconciled against any actual use of the logs.

The second-order impact is operational noise. A '$logs' container holding years of entries is slower and more awkward to search when you genuinely need to investigate an incident, and the sheer volume can make the useful recent logs harder to find. Trimming retention to the window you actually query keeps the logs both cheaper and more useful.

There is no downside to acting that offsets the saving. You are deleting diagnostic logs, not application data, and only those older than a window you choose. The only thing to get right is sizing that window so any audit, security or troubleshooting requirement that genuinely needs older logs is still met, which for most accounts is a short period measured in days or weeks.

How do you cap classic log retention safely?

Work it in one pass: find the accounts, size the saving, set a retention period that still meets any genuine need for older logs, and decide where classic logging should simply be retired in favour of Azure Monitor.

1. Inventory classic logging across accounts

For each flagged account, check 'az storage logging show' to see which services have logging on and what the retention is. Accounts with logging on and retention at zero are the ones accruing unbounded cost. Note the size of the '$logs' container so you can prioritise by saving, not by account count.

2. Choose a retention period that meets real need

Pick a window that still satisfies any audit, security or troubleshooting requirement, then size the rest to what teams actually query, which is usually short. There is no single right answer, but most operational use of request logs falls within days to a few weeks. Document the chosen period so the choice is deliberate rather than accidental.

3. Set retention so Azure prunes for you

Apply the retention period per service. Azure then deletes log data older than the window on an ongoing basis, clearing the historical backlog and holding the container at a steady state. The change is immediate and touches only diagnostic logs, never application data.

4. Retire classic logging where it is unused

Microsoft recommends Azure Storage logs in Azure Monitor over classic Storage Analytics logging. On accounts where the classic logs are not actively used, the cleanest answer is to switch classic logging off entirely with 'az storage logging off' and, if logs are still needed, capture them through a diagnostic setting instead. For new accounts, govern blob lifecycle with a management policy so retention is set by design.

# 1. Check current classic logging settings for an account.
az storage logging show \
  --account-name logsheavyprod \
  --services bqt -o table

# 2. Cap retention: keep blob and queue request logs for 30 days, log read/write/delete.
#    Azure then deletes anything in $logs older than 30 days, on an ongoing basis.
az storage logging update \
  --account-name logsheavyprod \
  --services bq \
  --log rwd \
  --retention 30

# 3. Where classic logs are not used at all, retire classic logging entirely.
az storage logging off \
  --account-name logsheavyprod \
  --services bqt

# ----------------------------------------------------------------------------
# Declarative equivalent for new accounts. Classic logging retention is a
# data-plane property and is not set in Bicep, so govern the $logs blobs with a
# lifecycle management policy instead. This Bicep deletes blobs under the $logs
# prefix after 30 days, so retention is bounded by design rather than by drift.
# (Confirm the apiVersion against your target before deploying.)
#
# resource logRetentionPolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2025-01-01' = {
#   name: 'default'
#   parent: storageAccount
#   properties: {
#     policy: {
#       rules: [
#         {
#           enabled: true
#           name: 'expire-classic-logs'
#           type: 'Lifecycle'
#           definition: {
#             filters: {
#               blobTypes: [ 'blockBlob' ]
#               prefixMatch: [ '$logs' ]
#             }
#             actions: {
#               baseBlob: {
#                 delete: { daysAfterModificationGreaterThan: 30 }
#               }
#             }
#           }
#         }
#       ]
#     }
#   }
# }

Quick quiz

Question 1 of 5

Azure Advisor flags an account under 'Revisit retention policy for classic log data in storage accounts'. What is actually accruing cost?

You can now treat classic log retention as a clean, recurring saving: find the accounts where logging is on with no retention, size the saving by '$logs' container volume, set a retention period that still meets any genuine need, and retire classic logging in favour of Azure Monitor where the logs are unused. Azure then prunes stale logs for you and the line stops climbing.

Back to the library