My default · AWS · Logs, metrics and alarms

Amazon CloudWatch

Good features. Keep it for the logs you watch live and alarm on; send the chatty bulk through Firehose to S3.

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

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

Want this stack in your AWS account?

Cloudless Labs is a Sydney consultancy. We migrate on-premises systems to AWS, build serverless apps on this stack, and coach teams to ship with Claude Code and Codex.

Contact Us

For general inquiries, please contact us at:

For e-learning capabilities, please contact: