CloudWatch is fine. What isn't fine is a function that logs every payload it touches. Fix the logging, set retention, and the bill becomes boring.
At volume, I split the logs: WARN and ERROR go to CloudWatch, where I can watch and alarm on them; the chatty lines go through Firehose into S3 at about a tenth of the price, searchable with Athena or DuckDB when I need them.
Use it when
- WARN and ERROR lines, alarms, metric filters and Live Tail: the logs you need during an incident.
- Low-volume functions, where the bill stays small anyway.
Don't use it when
- Chatty DEBUG/INFO logs at volume: about $673 per TB in Sydney vs about $75 through your own Firehose logger.
- Lambda's built-in S3 destination as the cheap option: in Sydney it costs $0.335/GB, the same as Infrequent Access.
Pricing
Sydney: Lambda logs $0.67/GB ingested (the first discount starts at 10 TB a month); Infrequent Access class $0.335/GB; storage $0.033/GB-month. Lambda's built-in delivery to S3 also costs $0.335/GB. Free tier: 5 GB a month.
In my words: what hurts
- Cost, for chatty systems.
Gotchas, with fixes
Gotcha: Cost Explorer labels log ingestion 'PutLogEvents', which looks like a per-call charge. It's billed per GB ingested.
Fix: Find the log groups with the most IncomingBytes. The cost is in bytes, not calls.
Gotcha: Logging whole message payloads in high-throughput functions. One function produced 59% of a client's 1 TB a month.
Fix: Log IDs and errors, not payloads. If payloads must be kept, send them to S3 or sample them.
Gotcha: The default Text log format can't drop DEBUG and INFO lines before ingestion.
Fix: Switch Lambda to JSON log format with application log level WARN in production.
Gotcha: Log groups never expire by default.
Fix: Set retention on every log group in your Pulumi code.
Gotcha: Infrequent Access log groups are half price but drop Live Tail, metric filters, subscription filters and Embedded Metric Format, which silently breaks Powertools Metrics. A log group's class can't be changed later.
Fix: Use IA only for verbose groups you rarely read, and create a new group (repoint LoggingConfig) to switch.
Gotcha: API Gateway execution logs at INFO level log every request.
Fix: Keep access logs, turn execution logs down.
Provisioning
Official Pulumi package · Official Terraform provider
Instead, consider
- Amazon Data Firehose Side by side: chatty logs to S3 for about $0.04/GB, critical lines stay here.
- Cloudflare Workers Workers Logs: $0.25/GB from 1 December 2026.
Worked examples
Where it fits
- Logs without a shocking bill: Pick 01.
The critical lines: WARN and ERROR, alarms, metric filters, Live Tail. JSON log format, retention set, no payloads.
Sources
Last reviewed by Nicolas Dao