From 2444cf6c915eeff1d9267770b75fa5823428bb84 Mon Sep 17 00:00:00 2001 From: Eugene Cheung Date: Thu, 30 May 2024 11:35:34 -0400 Subject: [PATCH] feat(dynamo): add ability to alarm on min TTL deletions --- API.md | 51 +++++++ .../aws-dynamo/DynamoTableMetricFactory.ts | 18 ++- .../aws-dynamo/DynamoTableMonitoring.ts | 26 ++++ .../aws-dynamo/DynamoTableMonitoring.test.ts | 16 ++- .../DynamoTableMonitoring.test.ts.snap | 126 +++++++++++++++--- 5 files changed, 213 insertions(+), 24 deletions(-) diff --git a/API.md b/API.md index 5af3b107..5082383a 100644 --- a/API.md +++ b/API.md @@ -15319,6 +15319,7 @@ const dynamoTableMonitoringOptions: DynamoTableMonitoringOptions = { ... } | addAverageSuccessfulUpdateItemLatencyAlarm | {[ key: string ]: LatencyThreshold} | *No description.* | | addConsumedReadCapacityAlarm | {[ key: string ]: ConsumedCapacityThreshold} | *No description.* | | addConsumedWriteCapacityAlarm | {[ key: string ]: ConsumedCapacityThreshold} | *No description.* | +| addMinTimeToLiveDeletedItemCountAlarm | {[ key: string ]: MinUsageCountThreshold} | *No description.* | | addReadThrottledEventsCountAlarm | {[ key: string ]: ThrottledEventsThreshold} | *No description.* | | addSystemErrorCountAlarm | {[ key: string ]: ErrorCountThreshold} | *No description.* | | addWriteThrottledEventsCountAlarm | {[ key: string ]: ThrottledEventsThreshold} | *No description.* | @@ -15533,6 +15534,16 @@ public readonly addConsumedWriteCapacityAlarm: {[ key: string ]: ConsumedCapacit --- +##### `addMinTimeToLiveDeletedItemCountAlarm`Optional + +```typescript +public readonly addMinTimeToLiveDeletedItemCountAlarm: {[ key: string ]: MinUsageCountThreshold}; +``` + +- *Type:* {[ key: string ]: MinUsageCountThreshold} + +--- + ##### `addReadThrottledEventsCountAlarm`Optional ```typescript @@ -15597,6 +15608,7 @@ const dynamoTableMonitoringProps: DynamoTableMonitoringProps = { ... } | addAverageSuccessfulUpdateItemLatencyAlarm | {[ key: string ]: LatencyThreshold} | *No description.* | | addConsumedReadCapacityAlarm | {[ key: string ]: ConsumedCapacityThreshold} | *No description.* | | addConsumedWriteCapacityAlarm | {[ key: string ]: ConsumedCapacityThreshold} | *No description.* | +| addMinTimeToLiveDeletedItemCountAlarm | {[ key: string ]: MinUsageCountThreshold} | *No description.* | | addReadThrottledEventsCountAlarm | {[ key: string ]: ThrottledEventsThreshold} | *No description.* | | addSystemErrorCountAlarm | {[ key: string ]: ErrorCountThreshold} | *No description.* | | addWriteThrottledEventsCountAlarm | {[ key: string ]: ThrottledEventsThreshold} | *No description.* | @@ -15836,6 +15848,16 @@ public readonly addConsumedWriteCapacityAlarm: {[ key: string ]: ConsumedCapacit --- +##### `addMinTimeToLiveDeletedItemCountAlarm`Optional + +```typescript +public readonly addMinTimeToLiveDeletedItemCountAlarm: {[ key: string ]: MinUsageCountThreshold}; +``` + +- *Type:* {[ key: string ]: MinUsageCountThreshold} + +--- + ##### `addReadThrottledEventsCountAlarm`Optional ```typescript @@ -53960,6 +53982,7 @@ new DynamoTableMetricFactory(metricFactory: MetricFactory, props: DynamoTableMet | metricSystemErrorsCount | This represents the number of requests that resulted in a 500 (server error) error code. | | metricThrottledReadRequestCount | *No description.* | | metricThrottledWriteRequestCount | *No description.* | +| metricTimeToLiveDeletedItemCount | *No description.* | | metricWriteCapacityUtilizationPercentage | *No description.* | --- @@ -54037,6 +54060,12 @@ public metricThrottledReadRequestCount(): Metric | MathExpression public metricThrottledWriteRequestCount(): Metric | MathExpression ``` +##### `metricTimeToLiveDeletedItemCount` + +```typescript +public metricTimeToLiveDeletedItemCount(): Metric | MathExpression +``` + ##### `metricWriteCapacityUtilizationPercentage` ```typescript @@ -54315,7 +54344,9 @@ public createWriteCapacityWidget(width: number, height: number): GraphWidget | systemErrorMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | tableBillingMode | aws-cdk-lib.aws_dynamodb.BillingMode | *No description.* | | throttledEventsAnnotations | aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[] | *No description.* | +| timeToLiveDeletedItemCountMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | title | string | *No description.* | +| usageAlarmFactory | UsageAlarmFactory | *No description.* | | writeCapacityUsageMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | writeThrottleCountMetric | aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression | *No description.* | | tableUrl | string | *No description.* | @@ -54512,6 +54543,16 @@ public readonly throttledEventsAnnotations: HorizontalAnnotation[]; --- +##### `timeToLiveDeletedItemCountMetric`Required + +```typescript +public readonly timeToLiveDeletedItemCountMetric: Metric | MathExpression; +``` + +- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression + +--- + ##### `title`Required ```typescript @@ -54522,6 +54563,16 @@ public readonly title: string; --- +##### `usageAlarmFactory`Required + +```typescript +public readonly usageAlarmFactory: UsageAlarmFactory; +``` + +- *Type:* UsageAlarmFactory + +--- + ##### `writeCapacityUsageMetric`Required ```typescript diff --git a/lib/monitoring/aws-dynamo/DynamoTableMetricFactory.ts b/lib/monitoring/aws-dynamo/DynamoTableMetricFactory.ts index 15b789bf..e3536eb9 100644 --- a/lib/monitoring/aws-dynamo/DynamoTableMetricFactory.ts +++ b/lib/monitoring/aws-dynamo/DynamoTableMetricFactory.ts @@ -4,13 +4,10 @@ import { BillingMode, ITable, Operation } from "aws-cdk-lib/aws-dynamodb"; import { MetricFactory, MetricStatistic } from "../../common"; const DynamoDbNamespace = "AWS/DynamoDB"; -const ProvisionedReadCapacityUnitsMetric = "ProvisionedReadCapacityUnits"; -const ProvisionedWriteCapacityUnitsMetric = "ProvisionedWriteCapacityUnits"; const ProvisionedLabel = "Provisioned"; const ConsumedLabel = "Consumed"; const ReadThrottleEventsLabel = "Read"; const WriteThrottleEventsLabel = "Write"; -const SystemErrorsLabel = "System Errors"; export interface DynamoTableMetricFactoryProps { /** @@ -39,7 +36,7 @@ export class DynamoTableMetricFactory { metricProvisionedReadCapacityUnits() { return this.metricFactory.adaptMetric( - this.table.metric(ProvisionedReadCapacityUnitsMetric, { + this.table.metric("ProvisionedReadCapacityUnits", { label: ProvisionedLabel, statistic: MetricStatistic.AVERAGE, }) @@ -48,7 +45,7 @@ export class DynamoTableMetricFactory { metricProvisionedWriteCapacityUnits() { return this.metricFactory.adaptMetric( - this.table.metric(ProvisionedWriteCapacityUnitsMetric, { + this.table.metric("ProvisionedWriteCapacityUnits", { label: ProvisionedLabel, statistic: MetricStatistic.AVERAGE, }) @@ -195,7 +192,16 @@ export class DynamoTableMetricFactory { // the metric is not emitted until error happens Object.keys(usingMetrics).join("+"), usingMetrics, - SystemErrorsLabel + "System Errors" + ); + } + + metricTimeToLiveDeletedItemCount() { + return this.metricFactory.adaptMetric( + this.table.metric("TimeToLiveDeletedItemCount", { + label: "TTL Deleted Item Count", + statistic: MetricStatistic.MAX, + }) ); } } diff --git a/lib/monitoring/aws-dynamo/DynamoTableMonitoring.ts b/lib/monitoring/aws-dynamo/DynamoTableMonitoring.ts index e06fa3b1..3a6410be 100644 --- a/lib/monitoring/aws-dynamo/DynamoTableMonitoring.ts +++ b/lib/monitoring/aws-dynamo/DynamoTableMonitoring.ts @@ -5,6 +5,7 @@ import { IMetric, IWidget, LegendPosition, + TreatMissingData, } from "aws-cdk-lib/aws-cloudwatch"; import { BillingMode, @@ -36,12 +37,14 @@ import { LatencyThreshold, LatencyType, MetricWithAlarmSupport, + MinUsageCountThreshold, Monitoring, MonitoringScope, PercentageAxisFromZeroToHundred, QuarterWidth, ThrottledEventsThreshold, TimeAxisMillisFromZero, + UsageAlarmFactory, } from "../../common"; import { MonitoringHeaderWidget, @@ -68,6 +71,10 @@ export interface DynamoTableMonitoringOptions extends BaseMonitoringProps { >; readonly addSystemErrorCountAlarm?: Record; + readonly addMinTimeToLiveDeletedItemCountAlarm?: Record< + string, + MinUsageCountThreshold + >; readonly addAverageSuccessfulGetRecordsLatencyAlarm?: Record< string, @@ -120,6 +127,7 @@ export class DynamoTableMonitoring extends Monitoring { readonly errorAlarmFactory: ErrorAlarmFactory; readonly latencyAlarmFactory: LatencyAlarmFactory; readonly dynamoCapacityAlarmFactory: DynamoAlarmFactory; + readonly usageAlarmFactory: UsageAlarmFactory; readonly latencyAnnotations: HorizontalAnnotation[]; readonly errorCountAnnotations: HorizontalAnnotation[]; @@ -134,6 +142,7 @@ export class DynamoTableMonitoring extends Monitoring { readonly readThrottleCountMetric: MetricWithAlarmSupport; readonly writeThrottleCountMetric: MetricWithAlarmSupport; readonly systemErrorMetric: MetricWithAlarmSupport; + readonly timeToLiveDeletedItemCountMetric: MetricWithAlarmSupport; readonly latencyAverageSearchMetrics: IMetric; // keys are Operation, but JSII doesn't like non-string types readonly averagePerOperationLatencyMetrics: Record< @@ -166,6 +175,8 @@ export class DynamoTableMonitoring extends Monitoring { this.errorAlarmFactory = new ErrorAlarmFactory(this.alarmFactory); this.latencyAlarmFactory = new LatencyAlarmFactory(this.alarmFactory); this.dynamoCapacityAlarmFactory = new DynamoAlarmFactory(this.alarmFactory); + this.usageAlarmFactory = new UsageAlarmFactory(this.alarmFactory); + this.errorCountAnnotations = []; this.latencyAnnotations = []; this.dynamoReadCapacityAnnotations = []; @@ -189,6 +200,8 @@ export class DynamoTableMonitoring extends Monitoring { this.writeThrottleCountMetric = metricFactory.metricThrottledWriteRequestCount(); this.systemErrorMetric = metricFactory.metricSystemErrorsCount(); + this.timeToLiveDeletedItemCountMetric = + metricFactory.metricTimeToLiveDeletedItemCount(); this.latencyAverageSearchMetrics = metricFactory.metricSearchAverageSuccessfulRequestLatencyInMillis(); this.averagePerOperationLatencyMetrics = { @@ -293,6 +306,19 @@ export class DynamoTableMonitoring extends Monitoring { this.errorCountAnnotations.push(createdAlarm.annotation); this.addAlarm(createdAlarm); } + for (const disambiguator in props.addMinTimeToLiveDeletedItemCountAlarm) { + const alarmProps = { + // Missing data is bad if we expect TTL to be enabled + treatMissingDataOverride: TreatMissingData.BREACHING, + ...props.addMinTimeToLiveDeletedItemCountAlarm[disambiguator], + }; + const createdAlarm = this.usageAlarmFactory.addMinCountAlarm( + this.timeToLiveDeletedItemCountMetric, + alarmProps, + disambiguator + ); + this.addAlarm(createdAlarm); + } this.forEachOperationLatencyAlarmDefinition( Operation.GET_RECORDS, props.addAverageSuccessfulGetRecordsLatencyAlarm diff --git a/test/monitoring/aws-dynamo/DynamoTableMonitoring.test.ts b/test/monitoring/aws-dynamo/DynamoTableMonitoring.test.ts index 1bb9058d..a472387f 100644 --- a/test/monitoring/aws-dynamo/DynamoTableMonitoring.test.ts +++ b/test/monitoring/aws-dynamo/DynamoTableMonitoring.test.ts @@ -1,5 +1,6 @@ import { Duration, Stack } from "aws-cdk-lib"; import { Template } from "aws-cdk-lib/assertions"; +import { TreatMissingData } from "aws-cdk-lib/aws-cloudwatch"; import { AttributeType, BillingMode, Table } from "aws-cdk-lib/aws-dynamodb"; import { AlarmWithAnnotation, DynamoTableMonitoring } from "../../../lib"; @@ -62,6 +63,11 @@ test("snapshot test: all alarms", () => { evaluationPeriods: 8, }, }, + addMinTimeToLiveDeletedItemCountAlarm: { + Warning: { + minCount: 5, + }, + }, addReadThrottledEventsCountAlarm: { Warning: { maxThrottledEventsThreshold: 5, @@ -125,7 +131,7 @@ test("snapshot test: all alarms", () => { }); addMonitoringDashboardsToStack(stack, monitoring); - expect(numAlarmsCreated).toStrictEqual(14); + expect(numAlarmsCreated).toStrictEqual(15); expect(Template.fromStack(stack)).toMatchSnapshot(); }); @@ -187,6 +193,12 @@ test("snapshot test: pay-per-request, all alarms", () => { evaluationPeriods: 8, }, }, + addMinTimeToLiveDeletedItemCountAlarm: { + Warning: { + minCount: 5, + treatMissingDataOverride: TreatMissingData.MISSING, + }, + }, addReadThrottledEventsCountAlarm: { Warning: { maxThrottledEventsThreshold: 5, @@ -250,6 +262,6 @@ test("snapshot test: pay-per-request, all alarms", () => { }); addMonitoringDashboardsToStack(stack, monitoring); - expect(numAlarmsCreated).toStrictEqual(14); + expect(numAlarmsCreated).toStrictEqual(15); expect(Template.fromStack(stack)).toMatchSnapshot(); }); diff --git a/test/monitoring/aws-dynamo/__snapshots__/DynamoTableMonitoring.test.ts.snap b/test/monitoring/aws-dynamo/__snapshots__/DynamoTableMonitoring.test.ts.snap index ef0ffcab..4f02a069 100644 --- a/test/monitoring/aws-dynamo/__snapshots__/DynamoTableMonitoring.test.ts.snap +++ b/test/monitoring/aws-dynamo/__snapshots__/DynamoTableMonitoring.test.ts.snap @@ -78,7 +78,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageGetRecordsWarning82DF1F20", + "ScopeTestDummyTableMinUsageCountWarning9A39C286", "Arn", ], }, @@ -89,7 +89,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageQueryWarning49AF55CE", + "ScopeTestDummyTableLatencyAverageGetRecordsWarning82DF1F20", "Arn", ], }, @@ -100,7 +100,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageScanWarning609C9E1C", + "ScopeTestDummyTableLatencyAverageQueryWarning49AF55CE", "Arn", ], }, @@ -111,7 +111,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAveragePutItemWarningB14582BC", + "ScopeTestDummyTableLatencyAverageScanWarning609C9E1C", "Arn", ], }, @@ -122,7 +122,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageGetItemWarningE365AEB3", + "ScopeTestDummyTableLatencyAveragePutItemWarningB14582BC", "Arn", ], }, @@ -133,7 +133,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageUpdateItemWarning6A127C47", + "ScopeTestDummyTableLatencyAverageGetItemWarningE365AEB3", "Arn", ], }, @@ -144,7 +144,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageDeleteItemWarning13699989", + "ScopeTestDummyTableLatencyAverageUpdateItemWarning6A127C47", "Arn", ], }, @@ -155,7 +155,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageBatchGetItemWarning93533EB0", + "ScopeTestDummyTableLatencyAverageDeleteItemWarning13699989", "Arn", ], }, @@ -164,6 +164,17 @@ Object { "Ref": "AWS::Region", }, "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "ScopeTestDummyTableLatencyAverageBatchGetItemWarning93533EB0", + "Arn", + ], + }, + "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":12,\\"y\\":12,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ "ScopeTestDummyTableLatencyAverageBatchWriteItemWarning44120D91", @@ -638,6 +649,42 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, + "ScopeTestDummyTableMinUsageCountWarning9A39C286": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "The count is too low.", + "AlarmName": "Test-DummyTable-Min-Usage-Count-Warning", + "ComparisonOperator": "LessThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "TTL Deleted Item Count", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "TableName", + "Value": Object { + "Ref": "TableCD117FA1", + }, + }, + ], + "MetricName": "TimeToLiveDeletedItemCount", + "Namespace": "AWS/DynamoDB", + }, + "Period": 300, + "Stat": "Maximum", + }, + "ReturnData": true, + }, + ], + "Threshold": 5, + "TreatMissingData": "breaching", + }, + "Type": "AWS::CloudWatch::Alarm", + }, "ScopeTestDummyTableReadConsumedCapacityWarning52236D61": Object { "Properties": Object { "ActionsEnabled": true, @@ -1423,7 +1470,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageGetRecordsWarning82DF1F20", + "ScopeTestDummyTableMinUsageCountWarning9A39C286", "Arn", ], }, @@ -1434,7 +1481,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageQueryWarning49AF55CE", + "ScopeTestDummyTableLatencyAverageGetRecordsWarning82DF1F20", "Arn", ], }, @@ -1445,7 +1492,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageScanWarning609C9E1C", + "ScopeTestDummyTableLatencyAverageQueryWarning49AF55CE", "Arn", ], }, @@ -1456,7 +1503,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAveragePutItemWarningB14582BC", + "ScopeTestDummyTableLatencyAverageScanWarning609C9E1C", "Arn", ], }, @@ -1467,7 +1514,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageGetItemWarningE365AEB3", + "ScopeTestDummyTableLatencyAveragePutItemWarningB14582BC", "Arn", ], }, @@ -1478,7 +1525,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageUpdateItemWarning6A127C47", + "ScopeTestDummyTableLatencyAverageGetItemWarningE365AEB3", "Arn", ], }, @@ -1489,7 +1536,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageDeleteItemWarning13699989", + "ScopeTestDummyTableLatencyAverageUpdateItemWarning6A127C47", "Arn", ], }, @@ -1500,7 +1547,7 @@ Object { "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ - "ScopeTestDummyTableLatencyAverageBatchGetItemWarning93533EB0", + "ScopeTestDummyTableLatencyAverageDeleteItemWarning13699989", "Arn", ], }, @@ -1509,6 +1556,17 @@ Object { "Ref": "AWS::Region", }, "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "ScopeTestDummyTableLatencyAverageBatchGetItemWarning93533EB0", + "Arn", + ], + }, + "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":12,\\"y\\":12,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", Object { "Fn::GetAtt": Array [ "ScopeTestDummyTableLatencyAverageBatchWriteItemWarning44120D91", @@ -1975,6 +2033,42 @@ Object { }, "Type": "AWS::CloudWatch::Alarm", }, + "ScopeTestDummyTableMinUsageCountWarning9A39C286": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "The count is too low.", + "AlarmName": "Test-DummyTable-Min-Usage-Count-Warning", + "ComparisonOperator": "LessThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "TTL Deleted Item Count", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "TableName", + "Value": Object { + "Ref": "TableCD117FA1", + }, + }, + ], + "MetricName": "TimeToLiveDeletedItemCount", + "Namespace": "AWS/DynamoDB", + }, + "Period": 300, + "Stat": "Maximum", + }, + "ReturnData": true, + }, + ], + "Threshold": 5, + "TreatMissingData": "missing", + }, + "Type": "AWS::CloudWatch::Alarm", + }, "ScopeTestDummyTableReadConsumedCapacityWarning52236D61": Object { "Properties": Object { "ActionsEnabled": true,