CloudWatch log groups: retention, classes, tiering, encryption and Lambda log format

How log groups store and expire data — default never-expire retention and the allowed retention values, the 72-hour deletion lag, Standard, Infrequent Access and Delivery classes and what IA can't query, 2026 intelligent tiering, KMS encryption with the logs service principal and encryption-context condition, PutLogEvents batch rules (sequence tokens no longer matter), and Lambda's Text/JSON log format and log levels.

markdownreferencev4XCP5-0KJYstage: referencetrust: officialservice: cloudwatchinterface: anylog group retentionnever expirePutRetentionPolicy valuesretentionInDayslog retention deletion 72 hourslog class Standard Infrequent Access DeliveryLogs IA limitationsintelligent tiering logsCloudWatch Logs KMSassociate-kms-keylogs.region.amazonaws.com key policykms:EncryptionContext:aws:logs:arnPutLogEvents limitssequence token ignoredInvalidSequenceTokenExceptionrejectedLogEventsInfoLambda log format JSONLoggingConfig LogFormatApplicationLogLevel/aws/lambda log group

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

CloudWatch log groups

New log groups keep data forever (Never Expire) unless you set retention. Set it when the group is created, in IaC, because log groups that Lambda and other services create on first write have no retention.

Retention

  • Allowed values (days): 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653. To return to "never expire", call DeleteRetentionPolicy.
aws logs put-retention-policy --log-group-name /aws/lambda/orders --retention-in-days 30
  • Expired events are marked and then deleted, typically within 72 hours (occasionally longer). Once marked, they stop counting toward storage cost and storedBytes.
  • Lengthening retention can keep events that were marked but not yet deleted. To make sure data is gone, keep the shorter setting until 72 hours after the old expiry.

Classes and tiering

Class (LogGroupClass)UseLimits
STANDARDDefault; full features—
INFREQUENT_ACCESSLogs queried occasionally (forensics), at a lower ingestion price per GBLogs Insights works, plus PPL and SQL and data-protection masking since 2026-03-27. Not supported: pattern, diff, unmask, filterIndex. The always-present @ fields are generated for Standard groups only
DELIVERYListed in the SDK's enumNot described on the fetched pages

Whether a group's class can be changed after creation isn't stated on the fetched pages.

Intelligent tiering (account-level, since 2026-07-15):

  • Data unread for 30 days moves to Infrequent Access, and after 90 days to Archive Instant Access.
  • Reading old data moves it back to Standard for 30 days.
  • Queries work the same in every tier.

Encryption with a KMS key

Log groups are always encrypted. To use your key:

  1. Use a symmetric key. In its key policy, allow the logs service principal for the key's Region, scoped to the log group:
{
  "Effect": "Allow",
  "Principal": { "Service": "logs.<region>.amazonaws.com" },
  "Action": ["kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:Describe*"],
  "Resource": "*",
  "Condition": { "ArnEquals": {
    "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:<region>:<account-id>:log-group:<log-group-name>"
  } }
}

Use ArnLike with a wildcard to cover many groups.

  1. Associate the key: aws logs create-log-group --log-group-name <name> --kms-key-id <key-arn>, or aws logs associate-kms-key … on an existing group. The caller needs kms:DescribeKey, or the call fails with AccessDeniedException.
  2. Wait: association and disassociation take up to five minutes to apply.

If the key is disabled, CloudWatch Logs can't read data encrypted with it. If it is deleted or the permission removed, that data can't be retrieved again. disassociate-kms-key affects only new data. Key policy mechanics are in reference/kms/key-policies-and-errors.md.

Writing (PutLogEvents)

RuleValue
Batch size≤ 1,048,576 bytes: message bytes plus 26 bytes per event
Events per batch≤ 10,000
Event size≤ 1 MB
OrderChronological within a batch, or the call fails
Span≤ 24 hours between first and last event
TimestampsMilliseconds. More than 2 hours in the future, or older than 14 days or the retention period, are rejected individually (rejectedLogEventsInfo: tooNewLogEventStartIndex, tooOldLogEventEndIndex, expiredLogEventEndIndex), and the rest are stored

Sequence tokens are ignored now. Parallel writers to one stream are fine, and the old per-stream rate limit was replaced by a per-account limit you can raise. InvalidSequenceTokenException and DataAlreadyAcceptedException are no longer returned, so code that handles them is dead.

Lambda's log group and format

  • Lambda writes to the log group /aws/lambda/<function> by default (the hub's earlier docs; the format page doesn't restate it).
  • The execution role needs permission to write logs, normally through AWSLambdaBasicExecutionRole (guides/lambda/debug-failing-function.md).
  • Log format: --logging-config LogFormat=JSON (also in CloudFormation, SAM and the CDK). The default is Text; Lambda Managed Instances always use JSON.
  • In JSON, Node.js console.* lines become objects with timestamp, level, message and requestId.
  • Errors logged with several arguments add errorType, errorMessage and stackTrace.
  • Platform lines use time, type and record.
  • Switching to JSON without setting levels sets application and system levels to INFO, so console.debug output should be filtered out (the hub's reading of the level filter). Changing the format doesn't rewrite old logs.
  • Querying JSON-format Lambda logs: reference/cloudwatch/logs-insights-queries.md.

Read this document as markdown — the same bytes an agent receives.