Repository: cdklabs/cdk-monitoring-constructs (language: python)

Issue:
feat: add BaseMetricFactory
So we can later use it for #533.

---

_By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_
feat: allow specifying regions/accounts at a more granular level
This allows users to target different regions/account for specific things within a facade rather than relying on 1 facade per region/account with the facade's global settings, so something like:

```ts
this.facade
  .monitorDynamoTable({
    ...,
  })
  .monitorDynamoTable({
    ...,
    region: <some_other_region>,
    account: <some_other_account>,
  })
```

---

_By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_


Discussion / hints:

Fix patch:
diff --git a/.projen/tasks.json b/.projen/tasks.json
index b1c07e94..50b6d340 100644
--- a/.projen/tasks.json
+++ b/.projen/tasks.json
@@ -235,7 +235,7 @@
       "description": "Prepare a release from \"main\" branch",
       "env": {
         "RELEASE": "true",
-        "MAJOR": "7"
+        "MAJOR": "8"
       },
       "steps": [
         {
diff --git a/.projenrc.ts b/.projenrc.ts
index 0b71fcf7..741a1e27 100644
--- a/.projenrc.ts
+++ b/.projenrc.ts
@@ -18,7 +18,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
   keywords: ["cloudwatch", "monitoring"],
 
   defaultReleaseBranch: "main",
-  majorVersion: 7,
+  majorVersion: 8,
   stability: "experimental",
 
   cdkVersion: CDK_VERSION,
diff --git a/API.md b/API.md
index 54490dcb..aa31aa87 100644
--- a/API.md
+++ b/API.md
@@ -23898,6 +23898,34 @@ public readonly addRecordsThrottledAlarm: {[ key: string ]: RecordsThrottledThre
 
 ---
 
+### LambdaFunctionEnhancedMetricFactoryProps <a name="LambdaFunctionEnhancedMetricFactoryProps" id="cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps"></a>
+
+#### Initializer <a name="Initializer" id="cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps.Initializer"></a>
+
+```typescript
+import { LambdaFunctionEnhancedMetricFactoryProps } from 'cdk-monitoring-constructs'
+
+const lambdaFunctionEnhancedMetricFactoryProps: LambdaFunctionEnhancedMetricFactoryProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps.property.lambdaFunction">lambdaFunction</a></code> | <code>aws-cdk-lib.aws_lambda.IFunction</code> | *No description.* |
+
+---
+
+##### `lambdaFunction`<sup>Required</sup> <a name="lambdaFunction" id="cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps.property.lambdaFunction"></a>
+
+```typescript
+public readonly lambdaFunction: IFunction;
+```
+
+- *Type:* aws-cdk-lib.aws_lambda.IFunction
+
+---
+
 ### LambdaFunctionMetricFactoryProps <a name="LambdaFunctionMetricFactoryProps" id="cdk-monitoring-constructs.LambdaFunctionMetricFactoryProps"></a>
 
 #### Initializer <a name="Initializer" id="cdk-monitoring-constructs.LambdaFunctionMetricFactoryProps.Initializer"></a>
@@ -60452,13 +60480,13 @@ public readonly streamUrl: string;
 ```typescript
 import { LambdaFunctionEnhancedMetricFactory } from 'cdk-monitoring-constructs'
 
-new LambdaFunctionEnhancedMetricFactory(metricFactory: MetricFactory, lambdaFunction: IFunction)
+new LambdaFunctionEnhancedMetricFactory(metricFactory: MetricFactory, props: LambdaFunctionEnhancedMetricFactoryProps)
 ```
 
 | **Name** | **Type** | **Description** |
 | --- | --- | --- |
 | <code><a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactory.Initializer.parameter.metricFactory">metricFactory</a></code> | <code><a href="#cdk-monitoring-constructs.MetricFactory">MetricFactory</a></code> | *No description.* |
-| <code><a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactory.Initializer.parameter.lambdaFunction">lambdaFunction</a></code> | <code>aws-cdk-lib.aws_lambda.IFunction</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactory.Initializer.parameter.props">props</a></code> | <code><a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps">LambdaFunctionEnhancedMetricFactoryProps</a></code> | *No description.* |
 
 ---
 
@@ -60468,9 +60496,9 @@ new LambdaFunctionEnhancedMetricFactory(metricFactory: MetricFactory, lambdaFunc
 
 ---
 
-##### `lambdaFunction`<sup>Required</sup> <a name="lambdaFunction" id="cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactory.Initializer.parameter.lambdaFunction"></a>
+##### `props`<sup>Required</sup> <a name="props" id="cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactory.Initializer.parameter.props"></a>
 
-- *Type:* aws-cdk-lib.aws_lambda.IFunction
+- *Type:* <a href="#cdk-monitoring-constructs.LambdaFunctionEnhancedMetricFactoryProps">LambdaFunctionEnhancedMetricFactoryProps</a>
 
 ---
 
@@ -66835,12 +66863,13 @@ public addMinSecretCountAlarm(metric: Metric | MathExpression, props: MinSecretC
 ```typescript
 import { SecretsManagerMetricFactory } from 'cdk-monitoring-constructs'
 
-new SecretsManagerMetricFactory(metricFactory: MetricFactory)
+new SecretsManagerMetricFactory(metricFactory: MetricFactory, props: BaseMetricFactoryProps)
 ```
 
 | **Name** | **Type** | **Description** |
 | --- | --- | --- |
 | <code><a href="#cdk-monitoring-constructs.SecretsManagerMetricFactory.Initializer.parameter.metricFactory">metricFactory</a></code> | <code><a href="#cdk-monitoring-constructs.MetricFactory">MetricFactory</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.SecretsManagerMetricFactory.Initializer.parameter.props">props</a></code> | <code><a href="#cdk-monitoring-constructs.BaseMetricFactoryProps">BaseMetricFactoryProps</a></code> | *No description.* |
 
 ---
 
@@ -66850,6 +66879,12 @@ new SecretsManagerMetricFactory(metricFactory: MetricFactory)
 
 ---
 
+##### `props`<sup>Required</sup> <a name="props" id="cdk-monitoring-constructs.SecretsManagerMetricFactory.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#cdk-monitoring-constructs.BaseMetricFactoryProps">BaseMetricFactoryProps</a>
+
+---
+
 #### Methods <a name="Methods" id="Methods"></a>
 
 | **Name** | **Description** |
diff --git a/lib/monitoring/aws-ec2/EC2MetricFactory.ts b/lib/monitoring/aws-ec2/EC2MetricFactory.ts
index 4a43f7bb..454236fd 100644
--- a/lib/monitoring/aws-ec2/EC2MetricFactory.ts
+++ b/lib/monitoring/aws-ec2/EC2MetricFactory.ts
@@ -157,7 +157,7 @@ export class EC2MetricFactory extends BaseMetricFactory<EC2MetricFactoryProps> {
    * CloudWatch when the instance is not allocated a full processor core.
    */
   metricAverageCpuUtilisationPercent() {
-    return this.createMetrics("CPUUtilization", MetricStatistic.AVERAGE);
+    return this.metric("CPUUtilization", MetricStatistic.AVERAGE);
   }
 
   /**
@@ -197,7 +197,7 @@ export class EC2MetricFactory extends BaseMetricFactory<EC2MetricFactoryProps> {
    * This metric identifies the volume of incoming network traffic to a single instance.
    */
   metricAverageNetworkInRateBytes() {
-    return this.createMetrics("NetworkIn", MetricStatistic.AVERAGE);
+    return this.metric("NetworkIn", MetricStatistic.AVERAGE);
   }
 
   /**
@@ -205,7 +205,7 @@ export class EC2MetricFactory extends BaseMetricFactory<EC2MetricFactoryProps> {
    * This metric identifies the volume of outgoing network traffic from a single instance.
    */
   metricAverageNetworkOutRateBytes() {
-    return this.createMetrics("NetworkOut", MetricStatistic.AVERAGE);
+    return this.metric("NetworkOut", MetricStatistic.AVERAGE);
   }
 
   private createDiskMetrics(metricName: string, statistic: MetricStatistic) {
@@ -235,7 +235,7 @@ export class EC2MetricFactory extends BaseMetricFactory<EC2MetricFactoryProps> {
     });
   }
 
-  private createMetrics(metricName: string, statistic: MetricStatistic) {
+  private metric(metricName: string, statistic: MetricStatistic) {
     return this.strategy.createMetrics(
       this.metricFactory,
       metricName,
diff --git a/lib/monitoring/aws-kinesisanalytics/KinesisDataAnalyticsMetricFactory.ts b/lib/monitoring/aws-kinesisanalytics/KinesisDataAnalyticsMetricFactory.ts
index f0a0fa4e..a96a8f6f 100644
--- a/lib/monitoring/aws-kinesisanalytics/KinesisDataAnalyticsMetricFactory.ts
+++ b/lib/monitoring/aws-kinesisanalytics/KinesisDataAnalyticsMetricFactory.ts
@@ -39,35 +39,35 @@ export class KinesisDataAnalyticsMetricFactory extends BaseMetricFactory<Kinesis
   }
 
   metricKPUsCount() {
-    return this.generateMetric({
+    return this.metric({
       name: "KPUs",
       description: "Kinesis Processing Units",
     });
   }
 
   metricDowntimeMs() {
-    return this.generateMetric({
+    return this.metric({
       name: "downtime",
       description: "Downtime",
     });
   }
 
   metricUptimeMs() {
-    return this.generateMetric({
+    return this.metric({
       name: "uptime",
       description: "Uptime",
     });
   }
 
   metricFullRestartsCount() {
-    return this.generateMetric({
+    return this.metric({
       name: "fullRestarts",
       description: "Restarts",
     });
   }
 
   metricNumberOfFailedCheckpointsCount() {
-    return this.generateMetric({
+    return this.metric({
       name: "numberOfFailedCheckpoints",
       description: "Failed Checkpoints",
       metricStatistic: MetricStatistic.SUM,
@@ -75,14 +75,14 @@ export class KinesisDataAnalyticsMetricFactory extends BaseMetricFactory<Kinesis
   }
 
   metricLastCheckpointDurationMs() {
-    return this.generateMetric({
+    return this.metric({
       name: "lastCheckpointDuration",
       description: "Last Checkpoint Duration",
     });
   }
 
   metricLastCheckpointSizeBytes() {
-    return this.generateMetric({
+    return this.metric({
       name: "lastCheckpointSize",
       description: "Last Checkpoint Size",
       metricStatistic: MetricStatistic.SUM,
@@ -90,41 +90,41 @@ export class KinesisDataAnalyticsMetricFactory extends BaseMetricFactory<Kinesis
   }
 
   metricCpuUtilizationPercent() {
-    return this.generateMetric({
+    return this.metric({
       name: "cpuUtilization",
       description: "CPU Utilization",
     });
   }
 
   metricHeapMemoryUtilizationPercent() {
-    return this.generateMetric({
+    return this.metric({
       name: "heapMemoryUtilization",
       description: "Heap Memory Utilization",
     });
   }
 
   metricOldGenerationGCTimeMs() {
-    return this.generateMetric({
+    return this.metric({
       name: "oldGenerationGCTime",
       description: "GC Time",
     });
   }
 
   metricOldGenerationGCCount() {
-    return this.generateMetric({
+    return this.metric({
       name: "oldGenerationGCCount",
       metricStatistic: MetricStatistic.N,
       description: "GC Count",
     });
   }
 
-  private generateMetric(metricsSpec: MetricsSpec) {
+  private metric(metricsSpec: MetricsSpec) {
     return this.metricFactory.createMetric(
       metricsSpec.name,
-      metricsSpec.metricStatistic || MetricStatistic.AVERAGE,
+      metricsSpec.metricStatistic ?? MetricStatistic.AVERAGE,
       metricsSpec.description,
       this.dimensionsMap,
-      undefined, // the hex color code of the metric on a graph
+      undefined,
       "AWS/KinesisAnalytics",
     );
   }
diff --git a/lib/monitoring/aws-lambda/LambdaFunctionEnhancedMetricFactory.ts b/lib/monitoring/aws-lambda/LambdaFunctionEnhancedMetricFactory.ts
index 8854d8f6..a153fee0 100644
--- a/lib/monitoring/aws-lambda/LambdaFunctionEnhancedMetricFactory.ts
+++ b/lib/monitoring/aws-lambda/LambdaFunctionEnhancedMetricFactory.ts
@@ -1,16 +1,29 @@
 import { IFunction } from "aws-cdk-lib/aws-lambda";
 
-import { MetricFactory, MetricStatistic } from "../../common";
+import {
+  BaseMetricFactory,
+  BaseMetricFactoryProps,
+  MetricFactory,
+  MetricStatistic,
+} from "../../common";
 
 const LambdaInsightsNamespace = "LambdaInsights";
 
-export class LambdaFunctionEnhancedMetricFactory {
-  protected readonly metricFactory: MetricFactory;
+export interface LambdaFunctionEnhancedMetricFactoryProps
+  extends BaseMetricFactoryProps {
+  readonly lambdaFunction: IFunction;
+}
+
+export class LambdaFunctionEnhancedMetricFactory extends BaseMetricFactory<LambdaFunctionEnhancedMetricFactoryProps> {
   protected readonly lambdaFunction: IFunction;
 
-  constructor(metricFactory: MetricFactory, lambdaFunction: IFunction) {
-    this.metricFactory = metricFactory;
-    this.lambdaFunction = lambdaFunction;
+  constructor(
+    metricFactory: MetricFactory,
+    props: LambdaFunctionEnhancedMetricFactoryProps,
+  ) {
+    super(metricFactory, props);
+
+    this.lambdaFunction = props.lambdaFunction;
   }
 
   enhancedMetricMaxCpuTotalTime() {
diff --git a/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts b/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts
index 02ad07d6..1f0ed07b 100644
--- a/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts
+++ b/lib/monitoring/aws-lambda/LambdaFunctionMetricFactory.ts
@@ -166,9 +166,8 @@ export class LambdaFunctionMetricFactory extends BaseMetricFactory<LambdaFunctio
   }
 
   metricProvisionedConcurrencySpilloverRate() {
-    const metric = this.metricProvisionedConcurrencySpilloverInvocations();
     return this.metricFactory.toRate(
-      metric,
+      this.metricProvisionedConcurrencySpilloverInvocations(),
       this.rateComputationMethod,
       false,
       "pcsi",
diff --git a/lib/monitoring/aws-lambda/LambdaFunctionMonitoring.ts b/lib/monitoring/aws-lambda/LambdaFunctionMonitoring.ts
index ae90ad96..9e637f25 100644
--- a/lib/monitoring/aws-lambda/LambdaFunctionMonitoring.ts
+++ b/lib/monitoring/aws-lambda/LambdaFunctionMonitoring.ts
@@ -234,7 +234,7 @@ export class LambdaFunctionMonitoring extends Monitoring {
     if (props.lambdaInsightsEnabled) {
       this.enhancedMetricFactory = new LambdaFunctionEnhancedMetricFactory(
         scope.createMetricFactory(),
-        props.lambdaFunction,
+        props,
       );
       this.enhancedMonitoringMaxCpuTotalTimeMetric =
         this.enhancedMetricFactory.enhancedMetricMaxCpuTotalTime();
diff --git a/lib/monitoring/aws-secretsmanager/SecretsManagerMetricFactory.ts b/lib/monitoring/aws-secretsmanager/SecretsManagerMetricFactory.ts
index ef64dbd9..98327a9f 100644
--- a/lib/monitoring/aws-secretsmanager/SecretsManagerMetricFactory.ts
+++ b/lib/monitoring/aws-secretsmanager/SecretsManagerMetricFactory.ts
@@ -1,5 +1,10 @@
 import { Duration } from "aws-cdk-lib";
-import { MetricFactory, MetricStatistic } from "../../common";
+import {
+  BaseMetricFactory,
+  BaseMetricFactoryProps,
+  MetricFactory,
+  MetricStatistic,
+} from "../../common";
 
 const CLASS = "None";
 const DEFAULT_METRIC_PERIOD = Duration.hours(1);
@@ -9,11 +14,14 @@ const RESOURCE = "SecretCount";
 const SERVICE = "Secrets Manager";
 const TYPE = "Resource";
 
-export class SecretsManagerMetricFactory {
-  protected readonly metricFactory: MetricFactory;
+export type SecretsManagerMetricFactoryProps = BaseMetricFactoryProps;
 
-  constructor(metricFactory: MetricFactory) {
-    this.metricFactory = metricFactory;
+export class SecretsManagerMetricFactory extends BaseMetricFactory<SecretsManagerMetricFactoryProps> {
+  constructor(
+    metricFactory: MetricFactory,
+    props: SecretsManagerMetricFactoryProps,
+  ) {
+    super(metricFactory, props);
   }
 
   metricSecretCount() {
diff --git a/lib/monitoring/aws-secretsmanager/SecretsManagerMonitoring.ts b/lib/monitoring/aws-secretsmanager/SecretsManagerMonitoring.ts
index 5b4ca661..9bbfb5bf 100644
--- a/lib/monitoring/aws-secretsmanager/SecretsManagerMonitoring.ts
+++ b/lib/monitoring/aws-secretsmanager/SecretsManagerMonitoring.ts
@@ -64,6 +64,7 @@ export class SecretsManagerMonitoring extends Monitoring {
 
     const metricFactory = new SecretsManagerMetricFactory(
       scope.createMetricFactory(),
+      props,
     );
     this.secretsCountMetric = metricFactory.metricSecretCount();
 
diff --git a/lib/monitoring/fluentbit/FluentBitMetricFactory.ts b/lib/monitoring/fluentbit/FluentBitMetricFactory.ts
index 67678ff3..4f8887b1 100644
--- a/lib/monitoring/fluentbit/FluentBitMetricFactory.ts
+++ b/lib/monitoring/fluentbit/FluentBitMetricFactory.ts
@@ -6,9 +6,14 @@ import {
   FluentBitOutputMetricTag,
   FluentBitStorageMetricTag,
 } from "./FluentBitConstants";
-import { MetricFactory, MetricStatistic, MonitoringScope } from "../../common";
+import {
+  BaseMetricFactory,
+  BaseMetricFactoryProps,
+  MetricStatistic,
+  MonitoringScope,
+} from "../../common";
 
-export interface FluentBitMetricFactoryProps {
+export interface FluentBitMetricFactoryProps extends BaseMetricFactoryProps {
   /**
    * Namespace that metrics will be emitted to.
    * @default metric factory default
@@ -16,14 +21,14 @@ export interface FluentBitMetricFactoryProps {
   readonly namespace?: string;
 }
 
-export class FluentBitMetricFactory {
-  protected readonly metricFactory: MetricFactory;
+export class FluentBitMetricFactory extends BaseMetricFactory<FluentBitMetricFactoryProps> {
   protected readonly namespace: string;
   protected readonly scope: MonitoringScope;
 
   constructor(scope: MonitoringScope, props: FluentBitMetricFactoryProps) {
+    super(scope.createMetricFactory(), props);
+
     this.scope = scope;
-    this.metricFactory = scope.createMetricFactory();
     this.namespace =
       props.namespace ??
       this.metricFactory.getNamespaceWithFallback(props.namespace);
@@ -78,10 +83,9 @@ export class FluentBitMetricFactory {
           metricValue: `${valueString}`,
         },
       );
-      const metric = metricFilter.metric({
+      return metricFilter.metric({
         statistic: MetricStatistic.MAX,
       });
-      return metric;
     });
   }
 


Test patch:
diff --git a/test/facade/MonitoringFacade.test.ts b/test/facade/MonitoringFacade.test.ts
index be55390d..e0eb833e 100644
--- a/test/facade/MonitoringFacade.test.ts
+++ b/test/facade/MonitoringFacade.test.ts
@@ -1,11 +1,14 @@
-import { Stack } from "aws-cdk-lib";
+import { Duration, Stack } from "aws-cdk-lib";
 import { Capture, Template } from "aws-cdk-lib/assertions";
 import { TextWidget } from "aws-cdk-lib/aws-cloudwatch";
+import { Table } from "aws-cdk-lib/aws-dynamodb";
+import { Topic } from "aws-cdk-lib/aws-sns";
 import {
   DefaultDashboardFactory,
   DynamicDashboardFactory,
   MonitoringFacade,
   SingleWidgetDashboardSegment,
+  notifySns,
 } from "../../lib";
 
 describe("test of defaults", () => {
@@ -64,6 +67,34 @@ describe("test of defaults", () => {
     });
   });
 
+  test("typical usage", () => {
+    const stack = new Stack();
+    const onAlarmTopic = new Topic(stack, "OnAlarmTopic", {
+      topicName: "Alarm",
+    });
+    const facade = new MonitoringFacade(stack, "MyAppFacade", {
+      metricFactoryDefaults: {
+        region: "us-east-1",
+        account: "09876543210",
+      },
+      alarmFactoryDefaults: {
+        alarmNamePrefix: "MyApp",
+        actionsEnabled: true,
+        action: notifySns(onAlarmTopic),
+      },
+    });
+    facade.addLargeHeader("My App Dashboard").monitorDynamoTable({
+      table: Table.fromTableName(stack, "ImportedTable", "MyTableName"),
+      addAverageSuccessfulGetItemLatencyAlarm: {
+        Critical: {
+          maxLatency: Duration.seconds(10),
+        },
+      },
+    });
+
+    expect(Template.fromStack(stack)).toMatchSnapshot();
+  });
+
   test("SingleWidgetDashboardSegment is not displayed if addSegment overrides set to false", () => {
     // configure monitoring facade with dashboard factory which populates all three default dashboards
     const stack = new Stack();
diff --git a/test/facade/__snapshots__/MonitoringFacade.test.ts.snap b/test/facade/__snapshots__/MonitoringFacade.test.ts.snap
new file mode 100644
index 00000000..373c2ccb
--- /dev/null
+++ b/test/facade/__snapshots__/MonitoringFacade.test.ts.snap
@@ -0,0 +1,125 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`test of defaults typical usage 1`] = `
+Object {
+  "Parameters": Object {
+    "BootstrapVersion": Object {
+      "Default": "/cdk-bootstrap/hnb659fds/version",
+      "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+      "Type": "AWS::SSM::Parameter::Value<String>",
+    },
+  },
+  "Resources": Object {
+    "MyAppFacadeMyAppFacadeDashboardsDashboard951173E0": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"# My App Dashboard\\"}},{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"markdown\\":\\"### Dynamo Table **[ImportedTable](https://us-east-1.console.aws.amazon.com/dynamodb/home?region=us-east-1#tables:selected=MyTableName)**\\"}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":3,\\"x\\":0,\\"y\\":2,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Read Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"Consumed\\",\\"expression\\":\\"consumed_rcu_sum/PERIOD(consumed_rcu_sum)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\",\\"id\\":\\"consumed_read_cap\\"}],[\\"AWS/DynamoDB\\",\\"ConsumedReadCapacityUnits\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"consumed_rcu_sum\\"}],[\\"AWS/DynamoDB\\",\\"ProvisionedReadCapacityUnits\\",\\"TableName\\",\\"MyTableName\\",{\\"label\\":\\"Provisioned\\",\\"id\\":\\"provisioned_read_cap\\"}],[{\\"label\\":\\"Utilization\\",\\"expression\\":\\"100*(consumed_read_cap/provisioned_read_cap)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\",\\"yAxis\\":\\"right\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false},\\"right\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}},\\"legend\\":{\\"position\\":\\"right\\"}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":3,\\"x\\":0,\\"y\\":5,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Write Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"Consumed\\",\\"expression\\":\\"consumed_wcu_sum/PERIOD(consumed_wcu_sum)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\",\\"id\\":\\"consumed_write_cap\\"}],[\\"AWS/DynamoDB\\",\\"ConsumedWriteCapacityUnits\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"consumed_wcu_sum\\"}],[\\"AWS/DynamoDB\\",\\"ProvisionedWriteCapacityUnits\\",\\"TableName\\",\\"MyTableName\\",{\\"label\\":\\"Provisioned\\",\\"id\\":\\"provisioned_write_cap\\"}],[{\\"label\\":\\"Utilization\\",\\"expression\\":\\"100*(consumed_write_cap/provisioned_write_cap)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\",\\"yAxis\\":\\"right\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false},\\"right\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}},\\"legend\\":{\\"position\\":\\"right\\"}}},{\\"type\\":\\"metric\\",\\"width\\":9,\\"height\\":6,\\"x\\":6,\\"y\\":2,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Latency (Average)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\" \\",\\"expression\\":\\"SEARCH('{AWS/DynamoDB,TableName,Operation} TableName=\\\\\\"MyTableName\\\\\\" MetricName=\\\\\\"SuccessfulRequestLatency\\\\\\"', 'Average', 300)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"GetItem > 10000 for 3 datapoints within 15 minutes\\",\\"value\\":10000,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}},\\"legend\\":{\\"position\\":\\"right\\"}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":6,\\"x\\":15,\\"y\\":2,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Throttles\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"Read\\",\\"expression\\":\\"FILL(readThrottles,0)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\"}],[\\"AWS/DynamoDB\\",\\"ReadThrottleEvents\\",\\"TableName\\",\\"MyTableName\\",{\\"label\\":\\"Read\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"readThrottles\\"}],[{\\"label\\":\\"Write\\",\\"expression\\":\\"FILL(writeThrottles,0)\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\"}],[\\"AWS/DynamoDB\\",\\"WriteThrottleEvents\\",\\"TableName\\",\\"MyTableName\\",{\\"label\\":\\"Write\\",\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"writeThrottles\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":6,\\"x\\":18,\\"y\\":2,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[{\\"label\\":\\"System Errors\\",\\"expression\\":\\"systemErrorGetItem+systemErrorBatchGetItem+systemErrorScan+systemErrorQuery+systemErrorGetRecords+systemErrorPutItem+systemErrorDeleteItem+systemErrorUpdateItem+systemErrorBatchWriteItem\\",\\"accountId\\":\\"09876543210\\",\\"region\\":\\"us-east-1\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"GetItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorGetItem\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"BatchGetItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorBatchGetItem\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"Scan\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorScan\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"Query\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorQuery\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"GetRecords\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorGetRecords\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"PutItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorPutItem\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"DeleteItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorDeleteItem\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"UpdateItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorUpdateItem\\"}],[\\"AWS/DynamoDB\\",\\"SystemErrors\\",\\"Operation\\",\\"BatchWriteItem\\",\\"TableName\\",\\"MyTableName\\",{\\"stat\\":\\"Sum\\",\\"visible\\":false,\\"id\\":\\"systemErrorBatchWriteItem\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+        "DashboardName": "MyAppFacade",
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "MyAppFacadeMyAppImportedTableLatencyAverageGetItemCriticalCE2E24AD": Object {
+      "Properties": Object {
+        "ActionsEnabled": true,
+        "AlarmActions": Array [
+          Object {
+            "Ref": "OnAlarmTopicF22649A2",
+          },
+        ],
+        "AlarmDescription": "Average latency is too high.",
+        "AlarmName": "MyApp-ImportedTable-Latency-Average-GetItem-Critical",
+        "ComparisonOperator": "GreaterThanThreshold",
+        "DatapointsToAlarm": 3,
+        "EvaluationPeriods": 3,
+        "Metrics": Array [
+          Object {
+            "Id": "m1",
+            "Label": "GetItem",
+            "MetricStat": Object {
+              "Metric": Object {
+                "Dimensions": Array [
+                  Object {
+                    "Name": "Operation",
+                    "Value": "GetItem",
+                  },
+                  Object {
+                    "Name": "TableName",
+                    "Value": "MyTableName",
+                  },
+                ],
+                "MetricName": "SuccessfulRequestLatency",
+                "Namespace": "AWS/DynamoDB",
+              },
+              "Period": 300,
+              "Stat": "Average",
+            },
+            "ReturnData": true,
+          },
+        ],
+        "Threshold": 10000,
+        "TreatMissingData": "notBreaching",
+      },
+      "Type": "AWS::CloudWatch::Alarm",
+    },
+    "OnAlarmTopicF22649A2": Object {
+      "Properties": Object {
+        "TopicName": "Alarm",
+      },
+      "Type": "AWS::SNS::Topic",
+    },
+  },
+  "Rules": Object {
+    "CheckBootstrapVersion": Object {
+      "Assertions": Array [
+        Object {
+          "Assert": Object {
+            "Fn::Not": Array [
+              Object {
+                "Fn::Contains": Array [
+                  Array [
+                    "1",
+                    "2",
+                    "3",
+                    "4",
+                    "5",
+                  ],
+                  Object {
+                    "Ref": "BootstrapVersion",
+                  },
+                ],
+              },
+            ],
+          },
+          "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+        },
+      ],
+    },
+  },
+}
+`;