API Gateway supports CloudWatch Logs delivery. I tried 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 allows recording events up to 1MB. Payloads exceeding 1MB continue to be truncated.
I configured both the traditional execution logs and this new delivery method, and compared how logs for the same request appear.
Verification Details
I created a minimal REST API and Lambda using CloudFormation, then added configuration to deliver execution logs to both CloudWatch Logs and S3. I sent the same requests before and after adding the delivery, and reviewed the logs in both the automatically managed log group and each delivery destination.
Verification Environment
Since differences between CloudFormation property constraints and values accepted by the CLI affect results, I am noting the environment used.
| 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, cloudWatchRoleArn must be configured per account and region. In this verification account, I reused an already-configured role. If not yet configured, grant AmazonAPIGatewayPushToCloudWatchLogs to a role that trusts apigateway.amazonaws.com. Set the ARN of that role using aws apigateway update-account. Since this value is shared across the entire account and region, it is not included 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"
}
In the stage, I set LoggingLevel to INFO and DataTraceEnabled to true. Unless loggingLevel is INFO or ERROR, execution log events will not be generated at all. A delivery consists of three resources: a DeliverySource as the source, a DeliveryDestination as the destination, and a Delivery connecting the two. Below is an excerpt defining a JSON destination for CloudWatch Logs and a JSON destination for S3.
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 to enable only standard execution logs. Since the template creates named IAM roles, CAPABILITY_NAMED_IAM must be specified.
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
DeliverySource must be created after ApiStage. In a template without DependsOn, DeliverySource became CREATE_FAILED. The error was Invalid stage identifier specified. The delivery source cannot be registered when execution logging is not enabled on the stage.
DestinationS3Json for S3 is created after the bucket policy is applied. The destination log group name does not need to be under /aws/vendedlogs/. A put-delivery-destination and create-delivery targeting /apigw-exec-logs-demo/v4-prefix-test succeeded. When RecordFields is omitted, the following 7 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 confirm truncation in the automatically managed log group before delivery, I sent a GET, a POST with a small body, a POST with a 4KB body, and a GET to a non-existent path. The first three returned 200, and the non-existent path returned 403. The 4KB body was generated using the following script, which concatenates 55 items each with a 40-character dummy value.
#!/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 a 4,333-byte JSON 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
(omitted)
aaabbbbbbbbbbccccccccccdddddddddd"},{"id":12,"key":"item-012","value":"aaaaaaa [TRUNCATED]
Adding Delivery
I redeployed using the same template with EnableLogDelivery=true. Two log groups, one 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, and CloudWatch Logs in plain format.
How It Looks at the Destination
For a POST request with a 4KB body, a structured record arrived in JSON format at CloudWatch Logs. The entire event was 5,198 bytes, and no [TRUNCATED] was 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\"},(中略)]}"
}
In a delivery where only payload was specified in RecordFields and the plain format was selected, only the same text as traditional execution logs arrived as a single event. This format can also be selected when using a parser that expects 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}
The Method request body before transformations for the same request was compared before and after delivery.
| Destination | Event size in bytes | Truncation |
|---|---|---|
| Auto-managed log group (before delivery) | 1,036 | Yes ([TRUNCATED]) |
| Custom log group (json delivery) | 5,198 | No |
| Custom log group (plain delivery, payload only) | 4,416 | No |
For this 4KB request, the body was not truncated in either JSON or plain delivery. The output format can be selected per destination. For CloudWatch Logs it is json / plain, for S3 it is json / plain / w3c / parquet, and for Firehose it is json / plain. For details, refer to the official documentation for log delivery.
In the log group with JSON delivery, fields assigned during delivery could be searched 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/{AccountID}/APIGateway/ExecutionLogs/{Region}/{REST API ID}/{Stage}/. The file name includes a timestamp, and a gzip-compressed object of 6,909 bytes 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 extracted file was JSON with one record per line, and the 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 of the curl execution (2026-09-13T05:54:38Z) as a starting point, the first arrival time at each destination was also verified.
| Destination | Value used to determine arrival time | Arrival time | Time from starting point |
|---|---|---|---|
| Custom log group (json) | @ingestionTime |
2026-09-13T05:54:52Z | Approx. 14 seconds |
| S3 bucket | Object LastModified |
2026-09-13T05:59:09Z | Approx. 4 minutes 31 seconds |
For this request, CloudWatch Logs arrived first. Note that execution log delivery is best-effort, and it is explicitly stated in the official documentation that logs may not always be delivered.
Stopping Logging to the Auto-Managed Log Group
For the four requests executed after creating the delivery, the auto-managed log group was checked for entries from the time of the curl execution onward.
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 CloudWatch Logs delivery is configured, 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 as a delivery destination.
Pricing
CloudWatch Logs delivery is charged at tiered Vended Logs rates based on monthly data volume. The unit prices below are from the calculation example for Northern Virginia 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. Delivery charges apply even when the destination is S3, and they appear in billing as <Region>-S3-Egress-Bytes. S3 storage charges and charges for optional format conversion such as Apache Parquet are not included in the amounts in the table. For Firehose destinations, Firehose ingestion charges also apply separately.
The traditional auto-managed log group uses standard CloudWatch Logs ingestion pricing. In the calculation example for Northern Virginia Standard class 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 price is at the same level.
Cost differences arise from the total bytes of logs subject to billing and storage costs at the destination. In the auto-managed log group, events are truncated at 1KB, but delivery records up to 1MB. For this 4KB request, the auto-managed log group was 1,036 bytes, while the JSON delivery was 5,198 bytes.
Since CloudWatch Logs delivery applies the Vended Logs pricing model, the unit price and tiers may differ from the traditional method. Additionally, since the truncation limit for logs is raised from 1KB to 1MB, and outputting in JSON format also increases record size, log volume may increase. In environments where large amounts of logs are generated, it is recommended to verify whether usage within the expected cost is achievable.
Summary
CloudWatch Logs delivery enables API Gateway REST API execution logs—which were previously truncated at 1KB and limited to CloudWatch Logs as the only output destination—to be recorded up to 1MB, delivered to S3 or Firehose, and saved in JSON or Parquet format.
When saved in JSON format, CloudWatch Logs enables Logs Insights searches with specified fields and Log Based Alarms based on those query results, while S3 makes it easier to perform analysis with tools such as Athena.
However, if the volume of logs recorded as Vended Logs increases, costs may be higher than with the traditional method, so it is recommended to verify after configuration that no unexpected costs are occurring.
