I checked the cost of S3 delivery with the new ALB log feature "CloudWatch Logs integration"
This page has been translated by machine translation. View original
Introduction
On July 23, 2026, there was an update integrating ALB logging into the CloudWatch Logs delivery feature (Vended Logs).
A previous article introduced log output to CloudWatch Logs.
This article examines the cost impact when delivering ALB logs to S3 using the CloudWatch Logs integration.
In this article, the conventional S3 output configured via ALB attributes (such as access_logs.s3.*) is referred to as the "legacy configuration."
Verification Details
This verification targeted ALB health check logs. Since they are less affected by actual access traffic and are output at regular intervals, they were considered suitable for comparing file sizes and output counts across formats.
The same health check logs were delivered in parallel to S3 in three formats — JSON, plain, and Parquet — to examine file sizes and the cost impact of S3 delivery via CloudWatch Logs integration.
Verification Environment
| Item | Value |
|---|---|
| Region | ap-northeast-1 |
| Load Balancer | 1 Application Load Balancer (<ALB_NAME>) |
| Target Log Type | ALB_HEALTH_CHECK_LOGS |
| Number of Log Fields | 10 |
| Health Check Interval | 30 seconds |
| Log File Output Interval | 5 minutes (per ALB node) |
| Output Formats | JSON / plain (space-delimited) / Parquet |
| Measurement Period | 2026-07-22 to 2026-07-27 (S3 delivery configuration implemented on 07-24) |
In this comparison, to avoid the impact of destination differences, all three formats were delivered to the same S3 bucket <LOG_BUCKET>, with only the prefix differing per format.
All size and cost figures below are based solely on health check logs.
Comparison by Format
File Size
One set of files containing 10 records, output from the same time and the same ALB node, was extracted and compared.
| Format | File Size | Per Record (estimated) | Ratio to plain (%) |
|---|---|---|---|
| plain (gz) | 283 B | 28.3 B | 100% |
| JSON (gz) | 393 B | 39.3 B | 139% |
| Parquet (internal GZIP) | 4,042 B | 404.2 B | 1,429% |
"Per Record (estimated)" is a reference value obtained by dividing the compressed file size by 10 records. Compression efficiency varies with the number of records, so it does not scale proportionally when the record count increases.
plain (Space-Delimited)
The plain format arranges values separated by spaces, the same as the legacy configuration.
http 2026-07-27T00:25:02.444270Z 0.022732728 <TARGET_IP>:3000 <TARGET_GROUP> PASS 200 - app/<ALB_NAME>/<ALB_ID> <ALB_NODE_IP>
JSON
JSON outputs each record as a single-line object.
{"type":"http","time":"2026-07-27T00:25:02.444270Z","latency":"0.022732728","target_addr":"<TARGET_IP>:3000","target_group_id":"<TARGET_GROUP>","status":"PASS","status_code":"200","reason_code":"-","elb":"app/<ALB_NAME>/<ALB_ID>","ip_address":"<ALB_NODE_IP>"}
The ratio changes with the number of fields (in the access log measurements in the previous article, JSON was 2.53 times the size of plain).
Since JSON pairs keys with values, it can be handled without relying on field position as with plain. JSON is easier to work with when anticipating future field additions.
Parquet
Reading Parquet files with pyarrow allowed us to check the proportion of metadata.
- rows=10, row_groups=1, columns=10
- Compression: GZIP
- Row group data section: 1,070 B
- Footer and schema metadata: approximately 2,972 B (about 73% of the entire file)
For output at the 5-minute interval and 10-record scale in this verification, Parquet is not suitable. Metadata accounts for approximately 73% of the total, and the large file size was more prominent than the benefits of columnar format compression and scan range narrowing. In addition, the official announcement states that Parquet conversion incurs an additional charge, with the unit price shown in the official blog for the US East (N. Virginia) region being $0.035/GB. There is no reason to choose this format for storage in S3 at this scale even in the Tokyo region.
Although outside the scope of this verification, if you want to store data in Parquet, another option is to batch-convert logs delivered in JSON or plain format using Athena CTAS or Glue ETL. Since the number of records per file can be increased, the proportion of metadata can be kept lower compared to saving small files directly as Parquet.
Actual Cost Measurement
Daily usage by usage type for ap-northeast-1 was checked in Cost Explorer. We compare 2026-07-22 and 07-23 (before configuration) with 2026-07-25 (the day after configuration).
| Date | S3 Recording | APN1-VendedLog-Bytes Usage (MB equivalent) |
|---|---|---|
| 2026-07-22 | None | 10.57 |
| 2026-07-23 | None | 10.75 |
| 2026-07-25 | Yes | 10.73 |
APN1-VendedLog-Bytes in Cost Explorer was converted to MB units for comparison. Even after configuring the CloudWatch Logs integration, this usage type remained within the range of 10.57–10.75 MB observed before configuration.
The approximately 10 MB recorded even before configuration is attributable to VPC flow logs running in the same account. Cost allocation tags were set on the flow log group, confirming that this usage type was generated only by the flow logs. No Vended Logs deliveries other than the ALB logs in this verification were configured.
The official announcement states that delivering ALB logs to Amazon S3 is free of charge for delivery. Delivery to CloudWatch Logs and Amazon Data Firehose is charged as Vended Logs. The comparison results for APN1-VendedLog-Bytes in this verification are also consistent with this pricing structure.
Configuration Procedure (Reference)
This section summarizes the configuration for delivering the same logs in parallel in multiple formats to S3, as done in this verification.
Parallel delivery in 3 formats via CLI
Create one Delivery Source, and create a Delivery Destination and Delivery for each of JSON, plain, and Parquet.
When switching formats in production, separate S3 buckets per format if possible to avoid mixing with existing logs. If using the same bucket, at minimum separate the prefixes.
First, create the Delivery Source from which the logs originate.
aws logs put-delivery-source \
--name alb-health-check-logs \
--resource-arn arn:aws:elasticloadbalancing:ap-northeast-1:<ACCOUNT_ID>:loadbalancer/app/<ALB_NAME>/<ALB_ID> \
--log-type ALB_HEALTH_CHECK_LOGS
In the verification, a Delivery Destination targeting the same S3 bucket was created for each format. Only --output-format is changed.
aws logs put-delivery-destination \
--name alb-vended-logs-s3-json \
--output-format json \
--delivery-destination-configuration destinationResourceArn=arn:aws:s3:::<LOG_BUCKET>
aws logs put-delivery-destination \
--name alb-vended-logs-s3-plain \
--output-format plain \
--delivery-destination-configuration destinationResourceArn=arn:aws:s3:::<LOG_BUCKET>
aws logs put-delivery-destination \
--name alb-vended-logs-s3-parquet \
--output-format parquet \
--delivery-destination-configuration destinationResourceArn=arn:aws:s3:::<LOG_BUCKET>
Finally, link them with Delivery. Change the destination ARN and suffixPath per format to prevent output from mixing within the same bucket.
aws logs create-delivery \
--delivery-source-name alb-health-check-logs \
--delivery-destination-arn arn:aws:logs:ap-northeast-1:<ACCOUNT_ID>:delivery-destination:alb-vended-logs-s3-json \
--s3-delivery-configuration 'suffixPath=health-check-logs/json/{region}/{yyyy}/{MM}/{dd}/'
Run create-delivery for plain and Parquet as well, changing the destination ARN and suffixPath accordingly.
S3 Bucket Policy
When using S3 as the destination, grant the following permissions to delivery.logs.amazonaws.com.
- Object write (
s3:PutObject) - Bucket ACL retrieval (
s3:GetBucketAcl)
{
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::<LOG_BUCKET>/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "<ACCOUNT_ID>"
}
}
}
{
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::<LOG_BUCKET>",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "<ACCOUNT_ID>"
}
}
}
In this verification, to simplify the setup, the condition in both statements was limited to aws:SourceAccount only, and aws:SourceArn was not specified. In production, it is recommended to also specify aws:SourceArn to restrict the delivery source.
Reasons to Migrate from Legacy Configuration to CloudWatch Logs Integration
As mentioned above, when delivering ALB logs to S3 via CloudWatch Logs integration, no Vended Logs delivery charges apply. S3 storage charges and request charges continue to occur as before. Note that when delivering in parallel in multiple formats as in this verification, the number of PutObject requests increases proportionally with the number of formats.
Log delivery definitions can be separated from ALB attributes. In this verification as well, all ALB log-related attributes remained disabled, yet logs could be delivered to S3 through the Delivery defined on the CloudWatch Logs side.
Even in a configuration that prioritizes cost by limiting log storage to S3only, the new method allows delivery to CloudWatch Logs log groups to be added as needed. This enables searching via Logs Insights and near-real-time review, which is useful during events or for incident investigation.
Additional delivery to a log group incurs CloudWatch Logs charges. It is also possible to keep storage to S3 only at normal times and add delivery to a log group only during the period before an event or when reproducing an incident. Please consider this as needed.
Summary
For new deployments storing ALB logs to S3, the CloudWatch Logs integration should be considered the first choice. Delivering to S3 incurs no Vended Logs delivery charges, output formats can be selected, and delivery to a log group can be added as needed for investigation via Logs Insights.
For format selection, plain is preferable if storage size is the priority, while JSON is easier to handle if you anticipate field additions or programmatic processing.
For environments using existing legacy configurations, it is recommended to review them when a maintenance window for the log analysis environment becomes available. Configure new log delivery to a different destination while keeping the legacy configuration enabled. Once the operation of log analysis and log processing pipelines has been verified, disabling the legacy configuration allows for a safe cutover.


