API Gateway Now Supports CloudWatch Logs Delivery: Trying Out Delivery to S3 and CloudWatch Logs
This page has been translated by machine translation. View original
Introduction
On September 10, 2026, it became possible to deliver API Gateway REST API execution logs via CloudWatch Logs delivery.
You can specify your own CloudWatch Logs log group, S3 bucket, or Firehose stream as the delivery destination. Standard execution logs truncate events at 1KB, but delivery can record events of up to 1MB. Payloads larger than 1MB are still truncated.
I configured both the conventional execution logs and this new delivery, and compared how the logs for the same request look.
What I Tested
I created a minimal REST API and Lambda with CloudFormation, and added settings to deliver execution logs to both CloudWatch Logs and S3. I ran the same request before and after adding the delivery, and checked the auto-managed log group and the logs at each delivery destination.
Test Environment
CloudFormation property constraints and differences in the values the CLI accepts affect the results, so here is the environment used this time.
| Item | Value |
|---|---|
| Region | ap-northeast-1 |
| AWS CLI | 2.36.44 |
| Lambda runtime | python3.13 |
| REST API | /echo (ANY, Lambda proxy integration, stage prod) |
| Stage settings | LoggingLevel: INFO / DataTraceEnabled: true |
Creating the Minimal Configuration
To output execution logs, you must set cloudWatchRoleArn for each account and region. In the test account this time, I reused an already configured role. If it is not set, attach AmazonAPIGatewayPushToCloudWatchLogs to a role that trusts apigateway.amazonaws.com. Then set the ARN of that role with aws apigateway update-account. This value is shared across the entire account and region, so I did not include it in the template.
aws apigateway get-account --region ap-northeast-1
{
"cloudwatchRoleArn": "arn:aws:iam::123456789012:role/example-role",
"throttleSettings": {
"burstLimit": 5000,
"rateLimit": 10000.0
},
"features": [],
"apiKeyVersion": "3"
}
For the stage, I set LoggingLevel to INFO and DataTraceEnabled to true. Unless loggingLevel is INFO or ERROR, no execution log events are generated at all. Delivery consists of three resources: a DeliverySource as the origin, a DeliveryDestination as the target, and a Delivery that connects the two. The following is an excerpt defining a CloudWatch Logs JSON destination and an S3 JSON destination.
ApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref RestApi
DeploymentId: !Ref Deployment
StageName: !Ref StageName
MethodSettings:
- ResourcePath: "/*"
HttpMethod: "*"
LoggingLevel: INFO
DataTraceEnabled: true
DeliverySource:
Type: AWS::Logs::DeliverySource
Condition: WithDelivery
DependsOn: ApiStage
Properties:
Name: !Sub "${StackPrefix}-source"
LogType: EXECUTION_LOGS
ResourceArn: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:${AWS::AccountId}:/restapis/${RestApi}/stages/${StageName}"
DestinationCwlJson:
Type: AWS::Logs::DeliveryDestination
Condition: WithDelivery
Properties:
Name: !Sub "${StackPrefix}-cwl-json"
DestinationResourceArn: !GetAtt DeliveryLogGroupJson.Arn
OutputFormat: json
DeliveryCwlJson:
Type: AWS::Logs::Delivery
Condition: WithDelivery
Properties:
DeliverySourceName: !Ref DeliverySource
DeliveryDestinationArn: !GetAtt DestinationCwlJson.Arn
DestinationS3Json:
Type: AWS::Logs::DeliveryDestination
Condition: WithDelivery
DependsOn: DeliveryBucketPolicy
Properties:
Name: !Sub "${StackPrefix}-s3-json"
DestinationResourceArn: !GetAtt DeliveryBucket.Arn
OutputFormat: json
DeliveryS3Json:
Type: AWS::Logs::Delivery
Condition: WithDelivery
Properties:
DeliverySourceName: !Ref DeliverySource
DeliveryDestinationArn: !GetAtt DestinationS3Json.Arn
First, I deployed with EnableLogDelivery set to false, enabling only the standard execution logs. The template creates a named IAM role, so specify CAPABILITY_NAMED_IAM.
aws cloudformation deploy \
--template-file apigw-exec-logs-demo.yaml \
--stack-name apigw-exec-logs-demo \
--parameter-overrides EnableLogDelivery=false \
--capabilities CAPABILITY_NAMED_IAM \
--region ap-northeast-1
aws cloudformation describe-stacks \
--stack-name apigw-exec-logs-demo \
--region ap-northeast-1 \
--query 'Stacks[0].Outputs'
Full CloudFormation template and constraints
AWSTemplateFormatVersion: "2010-09-09"
Description: >-
API Gateway REST API execution logs - CloudWatch Logs delivery (Vended Logs) verification stack.
Deploy with EnableLogDelivery=false first (standard execution logging only),
then redeploy with EnableLogDelivery=true to add the deliveries.
Parameters:
StackPrefix:
Type: String
Default: apigw-exec-logs-demo
Description: Prefix used for resource names.
StageName:
Type: String
Default: prod
EnableLogDelivery:
Type: String
Default: "false"
AllowedValues: ["true", "false"]
Description: >-
false = standard execution logging only (API Gateway managed log group).
true = create delivery source / destinations / deliveries.
LogRetentionInDays:
Type: Number
Default: 30
Conditions:
WithDelivery: !Equals [!Ref EnableLogDelivery, "true"]
Resources:
# ---------------------------------------------------------------
# NOTE: the account-level CloudWatch role for API Gateway
# (AWS::ApiGateway::Account / cloudWatchRoleArn) is intentionally NOT in this
# template. It is a single account/Region-wide setting shared by every REST
# API, so managing it here could overwrite or delete another API's setting.
# Configure it outside CloudFormation beforehand; see verification-procedure.md
# step 1 ("account level CloudWatch role").
# ---------------------------------------------------------------
# ---------------------------------------------------------------
# Lambda (echo backend)
# ---------------------------------------------------------------
FunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${StackPrefix}-lambda-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${StackPrefix}-fn"
RetentionInDays: !Ref LogRetentionInDays
Function:
Type: AWS::Lambda::Function
DependsOn: FunctionLogGroup
Properties:
FunctionName: !Sub "${StackPrefix}-fn"
Runtime: python3.13
Handler: index.lambda_handler
Role: !GetAtt FunctionRole.Arn
Timeout: 10
Code:
ZipFile: |
import json
def lambda_handler(event, context):
body = event.get("body") or ""
response = {
"path": event.get("path"),
"httpMethod": event.get("httpMethod"),
"queryStringParameters": event.get("queryStringParameters"),
"receivedBodyBytes": len(body.encode("utf-8")),
"echo": body[:200],
}
return {
"statusCode": 200,
"headers": {"content-type": "application/json"},
"body": json.dumps(response),
}
FunctionPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt Function.Arn
Action: lambda:InvokeFunction
Principal: apigateway.amazonaws.com
SourceArn: !Sub "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/*/*"
# ---------------------------------------------------------------
# REST API (minimal: /echo -> Lambda proxy)
# ---------------------------------------------------------------
RestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Ref StackPrefix
Description: Execution log delivery verification API
EndpointConfiguration:
Types: [REGIONAL]
EchoResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestApi
ParentId: !GetAtt RestApi.RootResourceId
PathPart: echo
EchoMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref RestApi
ResourceId: !Ref EchoResource
HttpMethod: ANY
# Verification-only endpoint: no authorizer. Do not copy this to production.
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations"
Deployment:
Type: AWS::ApiGateway::Deployment
DependsOn: EchoMethod
Properties:
RestApiId: !Ref RestApi
ApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref RestApi
DeploymentId: !Ref Deployment
StageName: !Ref StageName
MethodSettings:
- ResourcePath: "/*"
HttpMethod: "*"
LoggingLevel: INFO
DataTraceEnabled: true
# ---------------------------------------------------------------
# Delivery destinations (conditional)
# ---------------------------------------------------------------
DeliveryLogGroupJson:
Type: AWS::Logs::LogGroup
Condition: WithDelivery
Properties:
LogGroupName: !Sub "/aws/vendedlogs/apigateway/${StackPrefix}/${StageName}"
RetentionInDays: !Ref LogRetentionInDays
DeliveryLogGroupPlain:
Type: AWS::Logs::LogGroup
Condition: WithDelivery
Properties:
LogGroupName: !Sub "/aws/vendedlogs/apigateway/${StackPrefix}/${StageName}-plain"
RetentionInDays: !Ref LogRetentionInDays
DeliveryBucket:
Type: AWS::S3::Bucket
Condition: WithDelivery
Properties:
BucketName: !Sub "${StackPrefix}-${AWS::AccountId}-${AWS::Region}"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
# SSE-S3 (Amazon S3 managed keys). No KMS key is used: SSE-S3 needs no
# extra configuration and adds no key charges.
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
# Bucket policy per "Logs sent to Amazon S3" (V2 permissions):
# https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AWS-logs-infrastructure-V2-S3.html
DeliveryBucketPolicy:
Type: AWS::S3::BucketPolicy
Condition: WithDelivery
Properties:
Bucket: !Ref DeliveryBucket
PolicyDocument:
Version: "2012-10-17"
Id: AWSLogDeliveryWrite20150319
Statement:
- Sid: AWSLogDeliveryWrite
Effect: Allow
Principal:
Service: delivery.logs.amazonaws.com
Action: s3:PutObject
Resource: !Sub "${DeliveryBucket.Arn}/AWSLogs/${AWS::AccountId}/*"
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:delivery-source:*"
# ---------------------------------------------------------------
# Vended Logs delivery (conditional)
# ---------------------------------------------------------------
DeliverySource:
Type: AWS::Logs::DeliverySource
Condition: WithDelivery
# PutDeliverySource fails unless execution logging is already enabled on the
# stage, so the stage must exist with LoggingLevel INFO/ERROR first.
DependsOn: ApiStage
Properties:
Name: !Sub "${StackPrefix}-source"
LogType: EXECUTION_LOGS
ResourceArn: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:${AWS::AccountId}:/restapis/${RestApi}/stages/${StageName}"
# (1) own CloudWatch Logs log group, structured JSON (all record fields)
DestinationCwlJson:
Type: AWS::Logs::DeliveryDestination
Condition: WithDelivery
Properties:
Name: !Sub "${StackPrefix}-cwl-json"
DestinationResourceArn: !GetAtt DeliveryLogGroupJson.Arn
OutputFormat: json
DeliveryCwlJson:
Type: AWS::Logs::Delivery
Condition: WithDelivery
Properties:
DeliverySourceName: !Ref DeliverySource
DeliveryDestinationArn: !GetAtt DestinationCwlJson.Arn
# (2) S3 bucket, JSON
DestinationS3Json:
Type: AWS::Logs::DeliveryDestination
Condition: WithDelivery
DependsOn: DeliveryBucketPolicy
Properties:
Name: !Sub "${StackPrefix}-s3-json"
DestinationResourceArn: !GetAtt DeliveryBucket.Arn
OutputFormat: json
DeliveryS3Json:
Type: AWS::Logs::Delivery
Condition: WithDelivery
Properties:
DeliverySourceName: !Ref DeliverySource
DeliveryDestinationArn: !GetAtt DestinationS3Json.Arn
# (3) own log group, payload only (equivalent to standard execution log text).
# The CLI guidance uses --field-delimiter "" (empty string), but the
# CloudFormation property has a minimum length of 1, so it is omitted here.
# Verify whether RecordFields: [payload] alone reproduces the plain output.
DestinationCwlPlain:
Type: AWS::Logs::DeliveryDestination
Condition: WithDelivery
Properties:
Name: !Sub "${StackPrefix}-cwl-plain"
DestinationResourceArn: !GetAtt DeliveryLogGroupPlain.Arn
OutputFormat: plain
DeliveryCwlPlain:
Type: AWS::Logs::Delivery
Condition: WithDelivery
Properties:
DeliverySourceName: !Ref DeliverySource
DeliveryDestinationArn: !GetAtt DestinationCwlPlain.Arn
RecordFields:
- payload
Outputs:
ApiInvokeUrl:
Value: !Sub "https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageName}"
RestApiId:
Value: !Ref RestApi
StageArn:
Value: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:${AWS::AccountId}:/restapis/${RestApi}/stages/${StageName}"
AutoManagedLogGroupName:
Description: API Gateway managed log group (not managed by this stack; delete manually at teardown)
Value: !Sub "API-Gateway-Execution-Logs_${RestApi}/${StageName}"
DeliveryLogGroupJsonName:
Condition: WithDelivery
Value: !Ref DeliveryLogGroupJson
DeliveryLogGroupPlainName:
Condition: WithDelivery
Value: !Ref DeliveryLogGroupPlain
DeliveryBucketName:
Condition: WithDelivery
Value: !Ref DeliveryBucket
The DeliverySource must be created after the ApiStage is created. In a template without DependsOn, the DeliverySource ended up as CREATE_FAILED. The error was Invalid stage identifier specified. You cannot register a delivery source while execution logging is not enabled on the stage.
The S3 destination DestinationS3Json is created after the bucket policy is applied. The destination log group name does not need to be under /aws/vendedlogs/. put-delivery-destination and create-delivery succeeded with /apigw-exec-logs-demo/v4-prefix-test as the destination. When RecordFields is omitted, the following seven fields are selected by default.
{
"delivery": {
"id": "<delivery-id>",
"deliverySourceName": "apigw-exec-logs-demo-source",
"deliveryDestinationType": "CWL",
"recordFields": [
"resource_arn",
"event_timestamp",
"api_id",
"stage",
"resource_path",
"http_method",
"payload"
]
}
}
Execution Logs Before Delivery
To check truncation in the auto-managed log group before delivery, I ran a GET, a POST with a small body, a POST with 4KB, and a GET to a nonexistent path. The first three returned 200, and the nonexistent path returned 403. The 4KB body was generated with the following script, which lines up 55 dummy values of 40 characters each.
#!/usr/bin/env bash
# Generate a ~4KB JSON request body used to check the 1 KB truncation of
# standard execution logging. Dummy values only (no PII, no real domains).
#
# bash artifacts/make-payload-4kb.sh > artifacts/payload-4kb.json
# wc -c artifacts/payload-4kb.json
set -euo pipefail
n=${1:-55}
printf '{"note":"execution log truncation check","items":['
for i in $(seq 1 "$n"); do
[ "$i" -gt 1 ] && printf ','
printf '{"id":%d,"key":"item-%03d","value":"%s"}' \
"$i" "$i" "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
done
printf ']}\n'
bash make-payload-4kb.sh > payload-4kb.json
BASE=https://<rest-api-id>.execute-api.ap-northeast-1.amazonaws.com/prod
curl -s -i "$BASE/echo?name=kiro"
curl -s -i -X POST "$BASE/echo" -H 'content-type: application/json' -d '{"msg":"small"}'
curl -s -i -X POST "$BASE/echo" -H 'content-type: application/json' --data-binary @payload-4kb.json
curl -s -i "$BASE/notfound"
For the request that sent 4,333 bytes of JSON as the body, the Method request body before transformations event was 1,036 bytes. [TRUNCATED] was appended at the end. Endpoint request headers and Endpoint request body after transformations were also truncated to the same 1,036 bytes.
(05dd036b-14c9-4207-aa4f-0875c1a5c39a) Method request body before transformations: {"note":"execution log truncation check","items":[{"id":1,"key":"item-001","value":"aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"},{"id":2,"key":"item-002","value":"aaaaaaaaaabbbbbb
(中略)
aaabbbbbbbbbbccccccccccdddddddddd"},{"id":12,"key":"item-012","value":"aaaaaaa [TRUNCATED]
Adding the Delivery
I redeployed the same template with EnableLogDelivery=true. Two log groups, an S3 bucket, one DeliverySource, three DeliveryDestinations, and three Deliveries were added.
aws cloudformation deploy \
--template-file apigw-exec-logs-demo.yaml \
--stack-name apigw-exec-logs-demo \
--parameter-overrides EnableLogDelivery=true \
--capabilities CAPABILITY_NAMED_IAM \
--region ap-northeast-1
aws logs describe-deliveries --region ap-northeast-1
| delivery ID | Destination | OutputFormat | recordFields |
|---|---|---|---|
| <delivery-id-1> | Own log group | json | Not specified (default 7 fields) |
| <delivery-id-2> | Own log group (for plain) | plain | payload |
| <delivery-id-3> | S3 bucket | json | Not specified (default 7 fields) |
From a single DeliverySource, logs were delivered in parallel to CloudWatch Logs in JSON format, S3 in JSON format, and CloudWatch Logs in plain format.
How Logs Look at Each Destination
For the POST request that sent the 4KB body, a structured record arrived at the JSON-format CloudWatch Logs destination. The whole event was 5,198 bytes, and [TRUNCATED] was not appended to the payload.
{
"resource_arn": "arn:aws:apigateway:ap-northeast-1:123456789012:/restapis/<rest-api-id>/stages/prod",
"event_timestamp": 1789278878697,
"api_id": "<rest-api-id>",
"stage": "prod",
"resource_path": "/echo",
"http_method": "POST",
"payload": "(783aca98-1241-4a3a-a73c-b996b19046df) Method request body before transformations: {\"note\":\"execution log truncation check\",\"items\":[{\"id\":1,\"key\":\"item-001\",\"value\":\"aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd\"},(中略)]}"
}
For the delivery where I specified only payload in RecordFields and chose the plain format, only the same text as the conventional execution logs arrived as one event. You can choose this format when using a parser that assumes the existing text format.
(dc8caeee-4a2c-4829-accd-576372439c69) Starting execution for request: dc8caeee-4a2c-4829-accd-576372439c69
(dc8caeee-4a2c-4829-accd-576372439c69) HTTP Method: GET, Resource Path: /echo
(dc8caeee-4a2c-4829-accd-576372439c69) Method request query string: {name=kiro}
I compared the Method request body before transformations for the same request before and after delivery.
| Destination | Event size (bytes) | Truncation |
|---|---|---|
| Auto-managed log group (before delivery) | 1,036 | Yes ([TRUNCATED]) |
| Own log group (json delivery) | 5,198 | No |
| Own log group (plain delivery, payload only) | 4,416 | No |
With this 4KB request, the body was not truncated in either the JSON or the plain delivery. The output format can be chosen per destination. For CloudWatch Logs destinations it is json / plain, for S3 destinations json / plain / w3c / parquet, and for Firehose destinations json / plain. For details, see the official documentation on log delivery.
In the JSON delivery log group, I could search by specifying the fields added by delivery by name. The first query returned 20 rows, and the second query returned 3 rows: the 4KB POST, the small POST, and the GET.
fields @timestamp, api_id, stage, http_method, resource_path, @ingestionTime
| sort @timestamp desc
| limit 20
filter payload like /Method request body/
| fields @timestamp, resource_path, http_method, payload
| sort @timestamp desc
| limit 5
| @timestamp | resource_path | http_method |
|---|---|---|
| 2026-09-13 05:54:38.697 | /echo | POST |
| 2026-09-13 05:54:38.610 | /echo | POST |
| 2026-09-13 05:54:38.327 | /echo | GET |
In S3, objects were stored under the hierarchy AWSLogs/{account ID}/APIGateway/ExecutionLogs/{region}/{REST API ID}/{stage}/. The file name includes the date and time, and a gzip-compressed 6,909-byte object contained 57 records.
AWSLogs/123456789012/APIGateway/ExecutionLogs/ap-northeast-1/<rest-api-id>/prod/2026-09-13-05.APIGateway_<rest-api-id>_prod_2026-09-13-05_c4120841.log.gz
The decompressed file was JSON with one record per line, and its fields were the same as in the JSON delivery to CloudWatch Logs.
{"resource_arn":"arn:aws:apigateway:ap-northeast-1:123456789012:/restapis/<rest-api-id>/stages/prod","event_timestamp":1789278878606,"api_id":"<rest-api-id>","stage":"prod","resource_path":"/echo","http_method":"POST","payload":"(012d5149-bf27-4d3e-92c6-ba0e45aa3711) Extended Request Id: Dn4Y3HADNjMEKZA="}
Using the time the curl was executed (2026-09-13T05:54:38Z) as the starting point, I also checked the first arrival time at each destination.
| Destination | Value used to determine arrival time | Arrival time | Time from start |
|---|---|---|---|
| Own log group (json) | @ingestionTime |
2026-09-13T05:54:52Z | About 14 seconds |
| S3 bucket | Object LastModified |
2026-09-13T05:59:09Z | About 4 min 31 sec |
In this test, the CloudWatch Logs destination received the logs first. Note that the official documentation states explicitly that execution log delivery is best-effort and logs may not arrive.
Writes to the Auto-Managed Log Group Stop
For the four requests executed after creating the delivery, I filtered the auto-managed log group to the period after the curl execution time and checked it.
aws logs filter-log-events \
--log-group-name "API-Gateway-Execution-Logs_<rest-api-id>/prod" \
--start-time 1789278878000 \
--region ap-northeast-1
{
"events": [],
"searchedLogStreams": []
}
There were 0 matching events. When you configure CloudWatch Logs delivery, API Gateway stops writing to the auto-managed log group. If existing alarms or subscription filters reference the auto-managed log group, migrate them before switching, or include the same log group among the delivery destinations.
Pricing
CloudWatch Logs delivery is charged at tiered Vended Logs rates based on monthly data volume. The following unit prices are the values in the N. Virginia calculation example on the CloudWatch pricing page. Tiers reset every month.
| Monthly data volume | Unit price |
|---|---|
| 0–10TB | $0.50/GB |
| 10–30TB | $0.25/GB |
| 30–50TB | $0.10/GB |
| Over 50TB | $0.05/GB |
The amounts in the table are delivery charges. Even when the destination is S3, delivery charges apply, and they appear on the bill as <region>-S3-Egress-Bytes. S3 storage charges and charges for optional format conversion such as Apache Parquet are not included in the table amounts. For Firehose destinations, Firehose ingestion charges are also incurred separately.
The conventional auto-managed log group is charged at standard CloudWatch Logs ingestion rates. In the N. Virginia, Standard class calculation example on the same pricing page, ingestion was $0.50/GB and storage was $0.03/GB. The first tier of Vended Logs is also $0.50/GB, so the unit prices are at a similar level.
Cost differences arise from the total bytes of billable logs and the storage costs at the destination. In the auto-managed log group, events are truncated at 1KB, whereas delivery records up to 1MB. For this 4KB request, the auto-managed log group had 1,036 bytes, whereas the JSON delivery had 5,198 bytes.
Because the Vended Logs pricing structure applies to CloudWatch Logs delivery, unit prices and tiers may differ from the conventional method. In addition, the truncation limit was raised from 1 KB to 1 MB, and outputting in JSON format also increases the record size, so the log volume may increase. In environments that generate a lot of logs, I recommend checking that you can use it at the expected cost.
Summary
With CloudWatch Logs delivery, API Gateway REST API execution logs, which were previously truncated at 1KB and could only be output to CloudWatch Logs, can now be recorded up to 1MB, delivered to S3 and Firehose, and saved in formats such as JSON and Parquet.
Saving in JSON format lets you use Logs Insights searches that specify fields in CloudWatch Logs, as well as Log Based Alarms based on the results of those queries, and makes analysis with Athena and similar tools easier in S3.
However, if the volume of logs recorded as Vended Logs increases, costs may rise compared with the conventional method, so I recommend checking after setup that no unexpected costs are occurring.
