From 0e95bf0032f1beada8a1806724ef241613c3b41d Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Tue, 4 Jun 2024 05:27:08 +0900 Subject: [PATCH] feat(logs): add distribution property to the Subscription class (#30423) ### Issue # (if applicable) Closes #30422 ### Reason for this change Missing Property in the Subscription class. ### Description of changes Add destination property to the Subscription class. ### Description of how you validated changes Add unit tests and integ tests. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- ...ptionfilter-distribution-integ.assets.json | 19 ++ ...ionfilter-distribution-integ.template.json | 172 ++++++++++ .../cdk.out | 1 + .../integ.json | 12 + ...efaultTestDeployAssert24D5C536.assets.json | 19 ++ ...aultTestDeployAssert24D5C536.template.json | 36 ++ .../manifest.json | 143 ++++++++ .../tree.json | 312 ++++++++++++++++++ .../integ.subscriptionfilter-distribution.ts | 28 ++ packages/aws-cdk-lib/aws-logs/README.md | 23 +- .../aws-cdk-lib/aws-logs/lib/log-group.ts | 23 ++ .../aws-logs/lib/subscription-filter.ts | 13 +- .../aws-logs/test/subscriptionfilter.test.ts | 41 ++- 13 files changed, 838 insertions(+), 4 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.assets.json new file mode 100644 index 0000000000000..588d447b15995 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "8cfd85666486ac871e2126456898d2a31564c71962264569e5316a97b2b4b677": { + "source": { + "path": "aws-cdk-subscriptionfilter-distribution-integ.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "8cfd85666486ac871e2126456898d2a31564c71962264569e5316a97b2b4b677.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.template.json new file mode 100644 index 0000000000000..8b2c3bb1b6cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/aws-cdk-subscriptionfilter-distribution-integ.template.json @@ -0,0 +1,172 @@ +{ + "Resources": { + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "logs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "LogGroupSubscriptionCloudWatchLogsCanPutRecordsDefaultPolicyB7125314": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:ListShards", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Stream790BDEE4", + "Arn" + ] + } + }, + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LogGroupSubscriptionCloudWatchLogsCanPutRecordsDefaultPolicyB7125314", + "Roles": [ + { + "Ref": "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851" + } + ] + } + }, + "LogGroupSubscriptionE3573E29": { + "Type": "AWS::Logs::SubscriptionFilter", + "Properties": { + "DestinationArn": { + "Fn::GetAtt": [ + "Stream790BDEE4", + "Arn" + ] + }, + "Distribution": "Random", + "FilterName": "CustomSubscriptionFilterName", + "FilterPattern": "\"ERROR\" \"MainThread\"", + "LogGroupName": { + "Ref": "LogGroupF5B46931" + }, + "RoleArn": { + "Fn::GetAtt": [ + "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851", + "Arn" + ] + } + }, + "DependsOn": [ + "LogGroupSubscriptionCloudWatchLogsCanPutRecordsDefaultPolicyB7125314" + ] + }, + "Stream790BDEE4": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "RetentionPeriodHours": 24, + "ShardCount": 1, + "StreamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + }, + "Conditions": { + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integ.json new file mode 100644 index 0000000000000..056d02630c703 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "integ-test/DefaultTest": { + "stacks": [ + "aws-cdk-subscriptionfilter-distribution-integ" + ], + "assertionStack": "integ-test/DefaultTest/DeployAssert", + "assertionStackName": "integtestDefaultTestDeployAssert24D5C536" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json new file mode 100644 index 0000000000000..3555eb95abb24 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integtestDefaultTestDeployAssert24D5C536.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/manifest.json new file mode 100644 index 0000000000000..bcb55bdf1419e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/manifest.json @@ -0,0 +1,143 @@ +{ + "version": "36.0.0", + "artifacts": { + "aws-cdk-subscriptionfilter-distribution-integ.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-subscriptionfilter-distribution-integ.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-subscriptionfilter-distribution-integ": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-subscriptionfilter-distribution-integ.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/8cfd85666486ac871e2126456898d2a31564c71962264569e5316a97b2b4b677.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-subscriptionfilter-distribution-integ.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-subscriptionfilter-distribution-integ.assets" + ], + "metadata": { + "/aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupF5B46931" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupSubscriptionCloudWatchLogsCanPutRecordsDefaultPolicyB7125314" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupSubscriptionE3573E29" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/Stream/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Stream790BDEE4" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/AwsCdkKinesisEncryptedStreamsUnsupportedRegions": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsCdkKinesisEncryptedStreamsUnsupportedRegions" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-subscriptionfilter-distribution-integ/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-subscriptionfilter-distribution-integ" + }, + "integtestDefaultTestDeployAssert24D5C536.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtestDefaultTestDeployAssert24D5C536.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtestDefaultTestDeployAssert24D5C536": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtestDefaultTestDeployAssert24D5C536.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "metadata": { + "/integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/tree.json new file mode 100644 index 0000000000000..1d491c82370ca --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.js.snapshot/tree.json @@ -0,0 +1,312 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-subscriptionfilter-distribution-integ": { + "id": "aws-cdk-subscriptionfilter-distribution-integ", + "path": "aws-cdk-subscriptionfilter-distribution-integ", + "children": { + "LogGroup": { + "id": "LogGroup", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_logs.CfnLogGroup", + "version": "0.0.0" + } + }, + "Subscription": { + "id": "Subscription", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription", + "children": { + "CloudWatchLogsCanPutRecords": { + "id": "CloudWatchLogsCanPutRecords", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords", + "children": { + "ImportCloudWatchLogsCanPutRecords": { + "id": "ImportCloudWatchLogsCanPutRecords", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/ImportCloudWatchLogsCanPutRecords", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "logs.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/CloudWatchLogsCanPutRecords/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "kinesis:ListShards", + "kinesis:PutRecord", + "kinesis:PutRecords" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Stream790BDEE4", + "Arn" + ] + } + }, + { + "Action": "iam:PassRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "LogGroupSubscriptionCloudWatchLogsCanPutRecordsDefaultPolicyB7125314", + "roles": [ + { + "Ref": "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-subscriptionfilter-distribution-integ/LogGroup/Subscription/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::SubscriptionFilter", + "aws:cdk:cloudformation:props": { + "destinationArn": { + "Fn::GetAtt": [ + "Stream790BDEE4", + "Arn" + ] + }, + "distribution": "Random", + "filterName": "CustomSubscriptionFilterName", + "filterPattern": "\"ERROR\" \"MainThread\"", + "logGroupName": { + "Ref": "LogGroupF5B46931" + }, + "roleArn": { + "Fn::GetAtt": [ + "LogGroupSubscriptionCloudWatchLogsCanPutRecords29011851", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_logs.CfnSubscriptionFilter", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_logs.SubscriptionFilter", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_logs.LogGroup", + "version": "0.0.0" + } + }, + "Stream": { + "id": "Stream", + "path": "aws-cdk-subscriptionfilter-distribution-integ/Stream", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-subscriptionfilter-distribution-integ/Stream/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Kinesis::Stream", + "aws:cdk:cloudformation:props": { + "retentionPeriodHours": 24, + "shardCount": 1, + "streamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kinesis.CfnStream", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kinesis.Stream", + "version": "0.0.0" + } + }, + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "id": "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + "path": "aws-cdk-subscriptionfilter-distribution-integ/AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnCondition", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-subscriptionfilter-distribution-integ/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-subscriptionfilter-distribution-integ/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "integ-test": { + "id": "integ-test", + "path": "integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.ts new file mode 100644 index 0000000000000..1ca9b9daaea42 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.subscriptionfilter-distribution.ts @@ -0,0 +1,28 @@ +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { LogGroup, FilterPattern, Distribution } from 'aws-cdk-lib/aws-logs'; +import { KinesisDestination } from 'aws-cdk-lib/aws-logs-destinations'; +import { Stream } from 'aws-cdk-lib/aws-kinesis'; +class SubscriptionFilterDistributionIntegStack extends Stack { + constructor(scope: App, id: string, props?: StackProps) { + super(scope, id, props); + + const logGroup = new LogGroup(this, 'LogGroup'); + + const stream = new Stream(this, 'Stream'); + + logGroup.addSubscriptionFilter('Subscription', { + destination: new KinesisDestination(stream), + filterPattern: FilterPattern.allTerms('ERROR', 'MainThread'), + filterName: 'CustomSubscriptionFilterName', + distribution: Distribution.RANDOM, + }); + } +} + +const app = new App(); +const testCase = new SubscriptionFilterDistributionIntegStack(app, 'aws-cdk-subscriptionfilter-distribution-integ'); + +new IntegTest(app, 'integ-test', { + testCases: [testCase], +}); diff --git a/packages/aws-cdk-lib/aws-logs/README.md b/packages/aws-cdk-lib/aws-logs/README.md index ef56aa2ebaa30..2276fddfb2f7f 100644 --- a/packages/aws-cdk-lib/aws-logs/README.md +++ b/packages/aws-cdk-lib/aws-logs/README.md @@ -120,6 +120,25 @@ new logs.SubscriptionFilter(this, 'Subscription', { }); ``` +When you use `KinesisDestination`, you can choose the method used to +distribute log data to the destination by setting the `distribution` property. + +```ts +import * as destinations from 'aws-cdk-lib/aws-logs-destinations'; +import * as kinesis from 'aws-cdk-lib/aws-kinesis'; + +declare const stream: kinesis.Stream; +declare const logGroup: logs.LogGroup; + +new logs.SubscriptionFilter(this, 'Subscription', { + logGroup, + destination: new destinations.KinesisDestination(stream), + filterPattern: logs.FilterPattern.allTerms("ERROR", "MainThread"), + filterName: 'ErrorInMainThread', + distribution: logs.Distribution.RANDOM, +}); +``` + ## Metric Filters CloudWatch Logs can extract and emit metrics based on a textual log stream. @@ -344,12 +363,12 @@ For more information, see [Protect sensitive log data with masking](https://docs For a list of types of managed identifiers that can be audited and masked, see [Types of data that you can protect](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/protect-sensitive-log-data-types.html). -If a new identifier is supported but not yet in the `DataIdentifiers` enum, the name of the identifier can be supplied as `name` in the constructor instead. +If a new identifier is supported but not yet in the `DataIdentifiers` enum, the name of the identifier can be supplied as `name` in the constructor instead. To add a custom data identifier, supply a custom `name` and `regex` to the `CustomDataIdentifiers` constructor. For more information on custom data identifiers, see [Custom data identifiers](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL-custom-data-identifiers.html). -Each policy may consist of a log group, S3 bucket, and/or Firehose delivery stream audit destination. +Each policy may consist of a log group, S3 bucket, and/or Firehose delivery stream audit destination. Example: diff --git a/packages/aws-cdk-lib/aws-logs/lib/log-group.ts b/packages/aws-cdk-lib/aws-logs/lib/log-group.ts index fcb66ff83b220..b32bf0f3f5127 100644 --- a/packages/aws-cdk-lib/aws-logs/lib/log-group.ts +++ b/packages/aws-cdk-lib/aws-logs/lib/log-group.ts @@ -440,6 +440,21 @@ export interface LogGroupProps { readonly removalPolicy?: RemovalPolicy; } +/** + * The method used to distribute log data to the destination. + */ +export enum Distribution { + /** + * Log events from the same log stream are kept together and sent to the same destination. + */ + BY_LOG_STREAM = 'ByLogStream', + + /** + * Log events are distributed across the log destinations randomly. + */ + RANDOM = 'Random', +} + /** * Define a CloudWatch Log Group */ @@ -573,6 +588,14 @@ export interface SubscriptionFilterOptions { * @default Automatically generated */ readonly filterName?: string; + + /** + * The method used to distribute log data to the destination. + * This property can only be used with KinesisDestination. + * + * @default Distribution.BY_LOG_STREAM + */ + readonly distribution?: Distribution; } /** diff --git a/packages/aws-cdk-lib/aws-logs/lib/subscription-filter.ts b/packages/aws-cdk-lib/aws-logs/lib/subscription-filter.ts index bc2b18c719cc0..68ca728c858f4 100644 --- a/packages/aws-cdk-lib/aws-logs/lib/subscription-filter.ts +++ b/packages/aws-cdk-lib/aws-logs/lib/subscription-filter.ts @@ -2,7 +2,8 @@ import { Construct } from 'constructs'; import { ILogGroup, SubscriptionFilterOptions } from './log-group'; import { CfnSubscriptionFilter } from './logs.generated'; import * as iam from '../../aws-iam'; -import { Resource } from '../../core'; +import { KinesisDestination } from '../../aws-logs-destinations'; +import { Resource, Token } from '../../core'; /** * Interface for classes that can be the destination of a log Subscription @@ -57,6 +58,15 @@ export class SubscriptionFilter extends Resource { physicalName: props.filterName, }); + if ( + props.distribution && + !Token.isUnresolved(props.distribution) && + !Token.isUnresolved(props.destination) && + !(props.destination instanceof KinesisDestination) + ) { + throw new Error('distribution property can only be used with KinesisDestination.'); + } + const destProps = props.destination.bind(this, props.logGroup); new CfnSubscriptionFilter(this, 'Resource', { @@ -65,6 +75,7 @@ export class SubscriptionFilter extends Resource { roleArn: destProps.role && destProps.role.roleArn, filterPattern: props.filterPattern.logPatternString, filterName: this.physicalName, + distribution: props.distribution, }); } } diff --git a/packages/aws-cdk-lib/aws-logs/test/subscriptionfilter.test.ts b/packages/aws-cdk-lib/aws-logs/test/subscriptionfilter.test.ts index 1b03241f7f4c1..7001620709fd8 100644 --- a/packages/aws-cdk-lib/aws-logs/test/subscriptionfilter.test.ts +++ b/packages/aws-cdk-lib/aws-logs/test/subscriptionfilter.test.ts @@ -1,7 +1,9 @@ import { Construct } from 'constructs'; import { Template } from '../../assertions'; +import { Stream } from '../../aws-kinesis'; +import { KinesisDestination } from '../../aws-logs-destinations'; import { Stack } from '../../core'; -import { FilterPattern, ILogGroup, ILogSubscriptionDestination, LogGroup, SubscriptionFilter } from '../lib'; +import { Distribution, FilterPattern, ILogGroup, ILogSubscriptionDestination, LogGroup, SubscriptionFilter } from '../lib'; describe('subscription filter', () => { test('trivial instantiation', () => { @@ -45,6 +47,43 @@ describe('subscription filter', () => { FilterName: 'CustomSubscriptionFilterName', }); }); + + test('subscription filter with KinesisDestination can have distribution set.', () => { + // GIVEN + const stack = new Stack(); + const logGroup = new LogGroup(stack, 'LogGroup'); + + const stream = new Stream(stack, 'Stream'); + + // WHEN + new SubscriptionFilter(stack, 'Subscription', { + logGroup, + destination: new KinesisDestination(stream), + filterPattern: FilterPattern.literal('some pattern'), + filterName: 'CustomSubscriptionFilterName', + distribution: Distribution.RANDOM, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Logs::SubscriptionFilter', { + Distribution: 'Random', + }); + }); + + test('subscription filter with non-KinesisDestination can not have distribution set.', () => { + const stack = new Stack(); + const logGroup = new LogGroup(stack, 'LogGroup'); + + expect(() => { + new SubscriptionFilter(stack, 'Subscription', { + logGroup, + destination: new FakeDestination(), + filterPattern: FilterPattern.literal('some pattern'), + filterName: 'CustomSubscriptionFilterName', + distribution: Distribution.RANDOM, + }); + }).toThrow('distribution property can only be used with KinesisDestination.'); + }); }); class FakeDestination implements ILogSubscriptionDestination {