Most cost problems come from something running that shouldn't be. Logging is different. The data isn't running anywhere. It's just sitting there, and by default it sits there forever.
That's the whole problem. A log group created three years ago for a service that has since been rewritten is still holding every line it ever received, and you're still paying to store it. Nobody decided to keep it. Nobody decided to delete it either.
Where the money actually goes.
CloudWatch Logs has two costs that behave very differently.
Ingestion is charged on the volume of data you send in, and it depends on the log class of the log group. This is where a noisy service shows up: debug logging left on in production, a retry loop that logs every attempt, a health check that logs every request.
Storage is charged for as long as the data exists. AWS's own cost guidance describes storage as becoming the dominant driver over time, because those charges accumulate for the lifetime of the data. Stored data is compressed, so billed storage is smaller than the raw volume, but the meter never stops while the data is there.
The default that causes most of it.
A log group has no retention policy unless someone sets one. Without it, CloudWatch Logs stores the data indefinitely. Most teams create log groups through a framework, a Lambda deployment, or a managed service, and never see this setting. So the default quietly becomes the policy.
Three settings that control the bill.
1. Set retention on every log group. This is the highest-value change and the least exciting one. Pick a number that matches how far back you actually look, often 14 to 90 days for application logs, and apply it. If you need longer for compliance, export to S3 and let a cheaper storage class handle it (Issue #2 and Issue #11 cover how to pick one). AWS Config has a managed rule, cw-loggroup-retention-period-check, that finds log groups with no retention set. To catch new ones automatically, trigger a small function from EventBridge when a log group is created.
2. Use the Infrequent Access log class for logs you rarely read. AWS describes IA ingestion as typically about half the cost of Standard, though you should confirm against your region's pricing page. Storage and Logs Insights query pricing are the same in both classes, so the saving is on ingestion only. It suits verbose logs you only search when something breaks.
The catch is real. The class is chosen when the log group is created and can't be changed afterward. IA also doesn't support several features, including metric filters, subscription filters, Live Tail, and the GetLogEvents and FilterLogEvents API calls. If an alarm or a log shipper depends on any of those, the log group has to stay Standard. Decide before creating the group, and build it into your infrastructure code.
3. Turn off the noise at the source. The cheapest log line is the one never written. Check which log groups ingest the most and ask a boring question about each: does anyone read this? Debug-level logging in production and high-frequency health check logs are the usual answers.
Where to look first.
In Cost Explorer, filter to CloudWatch and group by usage type. That separates ingestion from storage. If storage is the bigger share, retention is your fix. If ingestion is bigger, look at the noisiest log groups and the log class. The StoredBytes metric in the AWS/Logs namespace shows how much each group is holding, and it's published once a day.
One newer option to know about. AWS has also described an Intelligent Tiering option for logs that moves data between Standard, Infrequent Access, and Archive tiers based on how recently it was accessed. It's enabled per account and region. It's worth reading about if your logs are mostly written and rarely read, but check its current availability and limits before relying on it, since it's newer than the rest of this.
Not on AWS?
The same pattern exists elsewhere. Azure Monitor Logs and Google Cloud Logging both charge for ingestion and for retention beyond a free period, and both let you set retention per destination. The names differ, the lesson doesn't: find out what your default retention is, because the default is the policy you didn't choose.
The actual takeaway: Log costs grow because deletion has no owner, the same pattern as the orphaned resources in Issue #7. Set retention on every log group, put rarely-read logs in a cheaper class at creation time, and stop writing lines nobody reads. Retention alone often does the most.
What's the oldest log group in your account, and does anyone still read it? Hit reply and tell me. I read every one.
