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

Issue:
[glue] Alarming support for failures
### Feature scope

AWS Glue

### Describe your suggested feature

Request from customer:

> We would like use this package for monitoring our AWS Glue jobs and alert when there is a failure.
> Currently the package neither has a metric nor an alarm for accomplishing the same.

https://docs.aws.amazon.com/glue/latest/dg/monitoring-awsglue-with-cloudwatch-metrics.html#awsglue-metrics


Discussion / hints:

Fix patch:
diff --git a/API.md b/API.md
index 7f1647e8..1fe2d70d 100644
--- a/API.md
+++ b/API.md
@@ -15507,6 +15507,10 @@ const glueJobMonitoringOptions: GlueJobMonitoringOptions = { ... }
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addToDetailDashboard">addToDetailDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to detailed dashboard. |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addToSummaryDashboard">addToSummaryDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to summary dashboard. |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.useCreatedAlarms">useCreatedAlarms</a></code> | <code><a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a></code> | Calls provided function to process all alarms created. |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addFailedTaskCountAlarm">addFailedTaskCountAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addFailedTaskRateAlarm">addFailedTaskRateAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addKilledTaskCountAlarm">addKilledTaskCountAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addKilledTaskRateAlarm">addKilledTaskRateAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}</code> | *No description.* |
 
 ---
 
@@ -15608,6 +15612,46 @@ Calls provided function to process all alarms created.
 
 ---
 
+##### `addFailedTaskCountAlarm`<sup>Optional</sup> <a name="addFailedTaskCountAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addFailedTaskCountAlarm"></a>
+
+```typescript
+public readonly addFailedTaskCountAlarm: {[ key: string ]: ErrorCountThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}
+
+---
+
+##### `addFailedTaskRateAlarm`<sup>Optional</sup> <a name="addFailedTaskRateAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addFailedTaskRateAlarm"></a>
+
+```typescript
+public readonly addFailedTaskRateAlarm: {[ key: string ]: ErrorRateThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}
+
+---
+
+##### `addKilledTaskCountAlarm`<sup>Optional</sup> <a name="addKilledTaskCountAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addKilledTaskCountAlarm"></a>
+
+```typescript
+public readonly addKilledTaskCountAlarm: {[ key: string ]: ErrorCountThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}
+
+---
+
+##### `addKilledTaskRateAlarm`<sup>Optional</sup> <a name="addKilledTaskRateAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringOptions.property.addKilledTaskRateAlarm"></a>
+
+```typescript
+public readonly addKilledTaskRateAlarm: {[ key: string ]: ErrorRateThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}
+
+---
+
 ### GlueJobMonitoringProps <a name="GlueJobMonitoringProps" id="cdk-monitoring-constructs.GlueJobMonitoringProps"></a>
 
 #### Initializer <a name="Initializer" id="cdk-monitoring-constructs.GlueJobMonitoringProps.Initializer"></a>
@@ -15629,6 +15673,10 @@ const glueJobMonitoringProps: GlueJobMonitoringProps = { ... }
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addToDetailDashboard">addToDetailDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to detailed dashboard. |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addToSummaryDashboard">addToSummaryDashboard</a></code> | <code>boolean</code> | Flag indicating if the widgets should be added to summary dashboard. |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.useCreatedAlarms">useCreatedAlarms</a></code> | <code><a href="#cdk-monitoring-constructs.IAlarmConsumer">IAlarmConsumer</a></code> | Calls provided function to process all alarms created. |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addFailedTaskCountAlarm">addFailedTaskCountAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addFailedTaskRateAlarm">addFailedTaskRateAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addKilledTaskCountAlarm">addKilledTaskCountAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}</code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.addKilledTaskRateAlarm">addKilledTaskRateAlarm</a></code> | <code>{[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}</code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMonitoringProps.property.jobName">jobName</a></code> | <code>string</code> | *No description.* |
 
 ---
@@ -15731,6 +15779,46 @@ Calls provided function to process all alarms created.
 
 ---
 
+##### `addFailedTaskCountAlarm`<sup>Optional</sup> <a name="addFailedTaskCountAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringProps.property.addFailedTaskCountAlarm"></a>
+
+```typescript
+public readonly addFailedTaskCountAlarm: {[ key: string ]: ErrorCountThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}
+
+---
+
+##### `addFailedTaskRateAlarm`<sup>Optional</sup> <a name="addFailedTaskRateAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringProps.property.addFailedTaskRateAlarm"></a>
+
+```typescript
+public readonly addFailedTaskRateAlarm: {[ key: string ]: ErrorRateThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}
+
+---
+
+##### `addKilledTaskCountAlarm`<sup>Optional</sup> <a name="addKilledTaskCountAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringProps.property.addKilledTaskCountAlarm"></a>
+
+```typescript
+public readonly addKilledTaskCountAlarm: {[ key: string ]: ErrorCountThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorCountThreshold">ErrorCountThreshold</a>}
+
+---
+
+##### `addKilledTaskRateAlarm`<sup>Optional</sup> <a name="addKilledTaskRateAlarm" id="cdk-monitoring-constructs.GlueJobMonitoringProps.property.addKilledTaskRateAlarm"></a>
+
+```typescript
+public readonly addKilledTaskRateAlarm: {[ key: string ]: ErrorRateThreshold};
+```
+
+- *Type:* {[ key: string ]: <a href="#cdk-monitoring-constructs.ErrorRateThreshold">ErrorRateThreshold</a>}
+
+---
+
 ##### `jobName`<sup>Required</sup> <a name="jobName" id="cdk-monitoring-constructs.GlueJobMonitoringProps.property.jobName"></a>
 
 ```typescript
@@ -39483,6 +39571,11 @@ new GlueJobMetricFactory(metricFactory: MetricFactory, jobName: string)
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricAverageExecutorCpuUsagePercentage">metricAverageExecutorCpuUsagePercentage</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricAverageExecutorMemoryUsagePercentage">metricAverageExecutorMemoryUsagePercentage</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricCompletedStagesSum">metricCompletedStagesSum</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricCompletedTasksSum">metricCompletedTasksSum</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricFailedTasksRate">metricFailedTasksRate</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricFailedTasksSum">metricFailedTasksSum</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricKilledTasksRate">metricKilledTasksRate</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricKilledTasksSum">metricKilledTasksSum</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricMaximumNeededExecutors">metricMaximumNeededExecutors</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricTotalReadBytesFromS3">metricTotalReadBytesFromS3</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.GlueJobMetricFactory.metricTotalWrittenBytesToS3">metricTotalWrittenBytesToS3</a></code> | *No description.* |
@@ -39513,6 +39606,36 @@ public metricAverageExecutorMemoryUsagePercentage(): Metric | MathExpression
 public metricCompletedStagesSum(): Metric | MathExpression
 ```
 
+##### `metricCompletedTasksSum` <a name="metricCompletedTasksSum" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricCompletedTasksSum"></a>
+
+```typescript
+public metricCompletedTasksSum(): Metric | MathExpression
+```
+
+##### `metricFailedTasksRate` <a name="metricFailedTasksRate" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricFailedTasksRate"></a>
+
+```typescript
+public metricFailedTasksRate(): Metric | MathExpression
+```
+
+##### `metricFailedTasksSum` <a name="metricFailedTasksSum" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricFailedTasksSum"></a>
+
+```typescript
+public metricFailedTasksSum(): Metric | MathExpression
+```
+
+##### `metricKilledTasksRate` <a name="metricKilledTasksRate" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricKilledTasksRate"></a>
+
+```typescript
+public metricKilledTasksRate(): Metric | MathExpression
+```
+
+##### `metricKilledTasksSum` <a name="metricKilledTasksSum" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricKilledTasksSum"></a>
+
+```typescript
+public metricKilledTasksSum(): Metric | MathExpression
+```
+
 ##### `metricMaximumNeededExecutors` <a name="metricMaximumNeededExecutors" id="cdk-monitoring-constructs.GlueJobMetricFactory.metricMaximumNeededExecutors"></a>
 
 ```typescript
@@ -48030,6 +48153,7 @@ create a two sets of dashboards: standard set (interactive) and a copy (bitmap).
 | <code><a href="#cdk-monitoring-constructs.ErrorType.READ_ERROR">READ_ERROR</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.ErrorType.WRITE_ERROR">WRITE_ERROR</a></code> | *No description.* |
 | <code><a href="#cdk-monitoring-constructs.ErrorType.EXPIRED">EXPIRED</a></code> | *No description.* |
+| <code><a href="#cdk-monitoring-constructs.ErrorType.KILLED">KILLED</a></code> | *No description.* |
 
 ---
 
@@ -48088,6 +48212,11 @@ create a two sets of dashboards: standard set (interactive) and a copy (bitmap).
 ---
 
 
+##### `KILLED` <a name="KILLED" id="cdk-monitoring-constructs.ErrorType.KILLED"></a>
+
+---
+
+
 ### GraphWidgetType <a name="GraphWidgetType" id="cdk-monitoring-constructs.GraphWidgetType"></a>
 
 #### Members <a name="Members" id="Members"></a>
diff --git a/lib/common/monitoring/alarms/ErrorAlarmFactory.ts b/lib/common/monitoring/alarms/ErrorAlarmFactory.ts
index a996a8a2..a2b42389 100644
--- a/lib/common/monitoring/alarms/ErrorAlarmFactory.ts
+++ b/lib/common/monitoring/alarms/ErrorAlarmFactory.ts
@@ -18,6 +18,7 @@ export enum ErrorType {
   READ_ERROR = "ReadError",
   WRITE_ERROR = "WriteError",
   EXPIRED = "Expired",
+  KILLED = "Killed",
 }
 
 export interface ErrorCountThreshold extends CustomAlarmThreshold {
diff --git a/lib/monitoring/aws-glue/GlueJobMetricFactory.ts b/lib/monitoring/aws-glue/GlueJobMetricFactory.ts
index d0a05542..7ca445f7 100644
--- a/lib/monitoring/aws-glue/GlueJobMetricFactory.ts
+++ b/lib/monitoring/aws-glue/GlueJobMetricFactory.ts
@@ -1,6 +1,10 @@
 import { DimensionsMap } from "aws-cdk-lib/aws-cloudwatch";
 
-import { MetricFactory, MetricStatistic } from "../../common";
+import {
+  MetricFactory,
+  MetricStatistic,
+  RateComputationMethod,
+} from "../../common";
 
 const GlueNamespace = "Glue";
 
@@ -83,6 +87,59 @@ export class GlueJobMetricFactory {
     );
   }
 
+  metricCompletedTasksSum() {
+    return this.metricFactory.createMetric(
+      "glue.driver.aggregate.numCompletedTasks",
+      MetricStatistic.SUM,
+      "Completed Tasks",
+      this.dimensionsMap,
+      undefined,
+      GlueNamespace
+    );
+  }
+
+  metricFailedTasksSum() {
+    return this.metricFactory.createMetric(
+      "glue.driver.aggregate.numFailedTasks",
+      MetricStatistic.SUM,
+      "Failed Tasks",
+      this.dimensionsMap,
+      undefined,
+      GlueNamespace
+    );
+  }
+
+  metricFailedTasksRate() {
+    return this.metricFactory.toRate(
+      this.metricFailedTasksSum(),
+      RateComputationMethod.AVERAGE,
+      true,
+      "killed",
+      false
+    );
+  }
+
+  metricKilledTasksSum() {
+    return this.metricFactory.createMetric(
+      "glue.driver.aggregate.numKilledTasks",
+      MetricStatistic.SUM,
+      "Killed Tasks",
+      this.dimensionsMap,
+      undefined,
+      GlueNamespace
+    );
+  }
+
+  metricKilledTasksRate() {
+    return this.metricFactory.toRate(
+      this.metricKilledTasksSum(),
+      RateComputationMethod.AVERAGE,
+      true,
+      "killed",
+      false
+    );
+  }
+
   metricMaximumNeededExecutors() {
     return this.metricFactory.createMetric(
       "glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors",
diff --git a/lib/monitoring/aws-glue/GlueJobMonitoring.ts b/lib/monitoring/aws-glue/GlueJobMonitoring.ts
index 88d55d70..82ed1667 100644
--- a/lib/monitoring/aws-glue/GlueJobMonitoring.ts
+++ b/lib/monitoring/aws-glue/GlueJobMonitoring.ts
@@ -1,16 +1,27 @@
-import { GraphWidget, IWidget } from "aws-cdk-lib/aws-cloudwatch";
+import {
+  GraphWidget,
+  HorizontalAnnotation,
+  IWidget,
+} from "aws-cdk-lib/aws-cloudwatch";
 
 import {
+  AlarmFactory,
   BaseMonitoringProps,
   CountAxisFromZero,
   DefaultGraphWidgetHeight,
   DefaultSummaryWidgetHeight,
+  ErrorAlarmFactory,
+  ErrorCountThreshold,
+  ErrorRateThreshold,
+  ErrorType,
+  HalfQuarterWidth,
   HalfWidth,
   MetricWithAlarmSupport,
   Monitoring,
   MonitoringScope,
   PercentageAxisFromZeroToHundred,
   QuarterWidth,
+  RateAxisFromZero,
   SizeAxisBytesFromZero,
 } from "../../common";
 import {
@@ -19,7 +30,12 @@ import {
 } from "../../dashboard";
 import { GlueJobMetricFactory } from "./GlueJobMetricFactory";
 
-export interface GlueJobMonitoringOptions extends BaseMonitoringProps {}
+export interface GlueJobMonitoringOptions extends BaseMonitoringProps {
+  readonly addFailedTaskCountAlarm?: Record<string, ErrorCountThreshold>;
+  readonly addFailedTaskRateAlarm?: Record<string, ErrorRateThreshold>;
+  readonly addKilledTaskCountAlarm?: Record<string, ErrorCountThreshold>;
+  readonly addKilledTaskRateAlarm?: Record<string, ErrorRateThreshold>;
+}
 
 export interface GlueJobMonitoringProps extends GlueJobMonitoringOptions {
   readonly jobName: string;
@@ -28,6 +44,12 @@ export interface GlueJobMonitoringProps extends GlueJobMonitoringOptions {
 export class GlueJobMonitoring extends Monitoring {
   protected readonly title: string;
 
+  protected readonly alarmFactory: AlarmFactory;
+  protected readonly errorAlarmFactory: ErrorAlarmFactory;
+
+  protected readonly errorCountAnnotations: HorizontalAnnotation[];
+  protected readonly errorRateAnnotations: HorizontalAnnotation[];
+
   protected readonly bytesReadFromS3Metric: MetricWithAlarmSupport;
   protected readonly bytesWrittenToS3Metric: MetricWithAlarmSupport;
   protected readonly cpuUsageMetric: MetricWithAlarmSupport;
@@ -35,6 +57,10 @@ export class GlueJobMonitoring extends Monitoring {
   protected readonly activeExecutorsMetric: MetricWithAlarmSupport;
   protected readonly completedStagesMetric: MetricWithAlarmSupport;
   protected readonly neededExecutorsMetric: MetricWithAlarmSupport;
+  protected readonly failedTaskCountMetric: MetricWithAlarmSupport;
+  protected readonly failedTaskRateMetric: MetricWithAlarmSupport;
+  protected readonly killedTaskCountMetric: MetricWithAlarmSupport;
+  protected readonly killedTaskRateMetric: MetricWithAlarmSupport;
 
   constructor(scope: MonitoringScope, props: GlueJobMonitoringProps) {
     super(scope, props);
@@ -50,15 +76,84 @@ export class GlueJobMonitoring extends Monitoring {
       scope.createMetricFactory(),
       props.jobName
     );
+
+    this.alarmFactory = this.createAlarmFactory(
+      namingStrategy.resolveAlarmFriendlyName()
+    );
+    this.errorAlarmFactory = new ErrorAlarmFactory(this.alarmFactory);
+
+    this.errorCountAnnotations = [];
+    this.errorRateAnnotations = [];
+
     this.bytesReadFromS3Metric = metricFactory.metricTotalReadBytesFromS3();
     this.bytesWrittenToS3Metric = metricFactory.metricTotalWrittenBytesToS3();
-    this.cpuUsageMetric =
-      metricFactory.metricAverageExecutorCpuUsagePercentage();
-    this.heapMemoryUsageMetric =
-      metricFactory.metricAverageExecutorMemoryUsagePercentage();
+    this.cpuUsageMetric = metricFactory
+      .metricAverageExecutorCpuUsagePercentage()
+      .with({ label: "CPU" });
+    this.heapMemoryUsageMetric = metricFactory
+      .metricAverageExecutorMemoryUsagePercentage()
+      .with({ label: "Heap" });
     this.activeExecutorsMetric = metricFactory.metricActiveExecutorsAverage();
     this.completedStagesMetric = metricFactory.metricCompletedStagesSum();
     this.neededExecutorsMetric = metricFactory.metricMaximumNeededExecutors();
+    this.failedTaskCountMetric = metricFactory
+      .metricFailedTasksSum()
+      .with({ label: "Failed" });
+    this.failedTaskRateMetric = metricFactory.metricFailedTasksRate();
+    this.killedTaskCountMetric = metricFactory
+      .metricKilledTasksSum()
+      .with({ label: "Killed" });
+    this.killedTaskRateMetric = metricFactory.metricKilledTasksRate();
+
+    for (const disambiguator in props.addFailedTaskCountAlarm) {
+      const alarmProps = props.addFailedTaskCountAlarm[disambiguator];
+      const createdAlarm = this.errorAlarmFactory.addErrorCountAlarm(
+        this.failedTaskCountMetric,
+        ErrorType.FAULT,
+        alarmProps,
+        disambiguator
+      );
+      this.errorCountAnnotations.push(createdAlarm.annotation);
+      this.addAlarm(createdAlarm);
+    }
+
+    for (const disambiguator in props.addFailedTaskRateAlarm) {
+      const alarmProps = props.addFailedTaskRateAlarm[disambiguator];
+      const createdAlarm = this.errorAlarmFactory.addErrorRateAlarm(
+        this.failedTaskRateMetric,
+        ErrorType.FAULT,
+        alarmProps,
+        disambiguator
+      );
+      this.errorRateAnnotations.push(createdAlarm.annotation);
+      this.addAlarm(createdAlarm);
+    }
+
+    for (const disambiguator in props.addKilledTaskCountAlarm) {
+      const alarmProps = props.addKilledTaskCountAlarm[disambiguator];
+      const createdAlarm = this.errorAlarmFactory.addErrorCountAlarm(
+        this.killedTaskCountMetric,
+        ErrorType.KILLED,
+        alarmProps,
+        disambiguator
+      );
+      this.errorCountAnnotations.push(createdAlarm.annotation);
+      this.addAlarm(createdAlarm);
+    }
+
+    for (const disambiguator in props.addKilledTaskRateAlarm) {
+      const alarmProps = props.addKilledTaskRateAlarm[disambiguator];
+      const createdAlarm = this.errorAlarmFactory.addErrorRateAlarm(
+        this.killedTaskRateMetric,
+        ErrorType.KILLED,
+        alarmProps,
+        disambiguator
+      );
+      this.errorRateAnnotations.push(createdAlarm.annotation);
+      this.addAlarm(createdAlarm);
+    }
+
+    props.useCreatedAlarms?.consume(this.createdAlarms());
   }
 
   summaryWidgets(): IWidget[] {
@@ -80,13 +175,11 @@ export class GlueJobMonitoring extends Monitoring {
       this.createJobExecutionWidget(QuarterWidth, DefaultGraphWidgetHeight),
       // Data Movement
       this.createDataMovementWidget(QuarterWidth, DefaultGraphWidgetHeight),
-      // CPU
-      this.createCpuUtilizationWidget(QuarterWidth, DefaultGraphWidgetHeight),
-      // Memory
-      this.createMemoryUtilizationWidget(
-        QuarterWidth,
-        DefaultGraphWidgetHeight
-      ),
+      // Usages
+      this.createUtilizationWidget(QuarterWidth, DefaultGraphWidgetHeight),
+      // Errors
+      this.createErrorCountWidget(HalfQuarterWidth, DefaultGraphWidgetHeight),
+      this.createErrorRateWidget(HalfQuarterWidth, DefaultGraphWidgetHeight),
     ];
   }
 
@@ -131,23 +224,25 @@ export class GlueJobMonitoring extends Monitoring {
     });
   }
 
-  protected createCpuUtilizationWidget(width: number, height: number) {
+  protected createErrorCountWidget(width: number, height: number) {
     return new GraphWidget({
       width,
       height,
-      title: "CPU Usage",
-      left: [this.cpuUsageMetric],
-      leftYAxis: PercentageAxisFromZeroToHundred,
+      title: "Errors",
+      left: [this.failedTaskCountMetric, this.killedTaskCountMetric],
+      leftYAxis: CountAxisFromZero,
+      leftAnnotations: this.errorCountAnnotations,
     });
   }
 
-  protected createMemoryUtilizationWidget(width: number, height: number) {
+  protected createErrorRateWidget(width: number, height: number) {
     return new GraphWidget({
       width,
       height,
-      title: "Memory Usage",
-      left: [this.heapMemoryUsageMetric],
-      leftYAxis: PercentageAxisFromZeroToHundred,
+      title: "Errors (rate)",
+      left: [this.failedTaskRateMetric, this.killedTaskRateMetric],
+      leftYAxis: RateAxisFromZero,
+      leftAnnotations: this.errorRateAnnotations,
     });
   }
 }


Test patch:
diff --git a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
index 333e1a83..b448bf89 100644
--- a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
+++ b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap
@@ -3464,15 +3464,19 @@ Object {
               Object {
                 "Ref": "AWS::Region",
               },
-              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.s3.filesystem.read_bytes\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Read (S3)\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.ALL.s3.filesystem.write_bytes\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Write (S3)\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"bytes\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU Usage\\",\\"region\\":\\"",
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.s3.filesystem.read_bytes\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Read (S3)\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.ALL.s3.filesystem.write_bytes\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Write (S3)\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"bytes\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Memory Usage\\",\\"region\\":\\"",
               Object {
                 "Ref": "AWS::Region",
               },
-              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU Usage (executor average)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":18,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Memory Usage\\",\\"region\\":\\"",
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":18,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"",
               Object {
                 "Ref": "AWS::Region",
               },
-              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"JVM Heap usage (executor average)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}}]}",
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":21,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}",
             ],
           ],
         },
@@ -3494,7 +3498,7 @@ Object {
               Object {
                 "Ref": "AWS::Region",
               },
-              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU Usage (executor average)\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"JVM Heap usage (executor average)\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}}]}",
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}}]}",
             ],
           ],
         },
diff --git a/test/monitoring/aws-glue/GlueJobMonitoring.test.ts b/test/monitoring/aws-glue/GlueJobMonitoring.test.ts
index 03c55547..2eb12261 100644
--- a/test/monitoring/aws-glue/GlueJobMonitoring.test.ts
+++ b/test/monitoring/aws-glue/GlueJobMonitoring.test.ts
@@ -1,17 +1,61 @@
 import { Stack } from "aws-cdk-lib";
 import { Template } from "aws-cdk-lib/assertions";
 
-import { GlueJobMonitoring } from "../../../lib";
+import { AlarmWithAnnotation, GlueJobMonitoring } from "../../../lib";
+import { addMonitoringDashboardsToStack } from "../../utils/SnapshotUtil";
 import { TestMonitoringScope } from "../TestMonitoringScope";
 
-test("snapshot test", () => {
+test("snapshot test: no alarms", () => {
   const stack = new Stack();
 
   const scope = new TestMonitoringScope(stack, "Scope");
 
-  new GlueJobMonitoring(scope, {
+  const monitoring = new GlueJobMonitoring(scope, {
     jobName: "DummyGlueJob",
   });
 
+  addMonitoringDashboardsToStack(stack, monitoring);
+  expect(Template.fromStack(stack)).toMatchSnapshot();
+});
+
+test("snapshot test: all alarms", () => {
+  const stack = new Stack();
+
+  const scope = new TestMonitoringScope(stack, "Scope");
+
+  let numAlarmsCreated = 0;
+
+  const monitoring = new GlueJobMonitoring(scope, {
+    jobName: "DummyGlueJob",
+    alarmFriendlyName: "DummyApi",
+    addKilledTaskCountAlarm: {
+      Warning: {
+        maxErrorCount: 3,
+      },
+    },
+    addKilledTaskRateAlarm: {
+      Warning: {
+        maxErrorRate: 2,
+      },
+    },
+    addFailedTaskCountAlarm: {
+      Warning: {
+        maxErrorCount: 3,
+      },
+    },
+    addFailedTaskRateAlarm: {
+      Warning: {
+        maxErrorRate: 4,
+      },
+    },
+    useCreatedAlarms: {
+      consume(alarms: AlarmWithAnnotation[]) {
+        numAlarmsCreated = alarms.length;
+      },
+    },
+  });
+
+  expect(numAlarmsCreated).toStrictEqual(4);
+  addMonitoringDashboardsToStack(stack, monitoring);
   expect(Template.fromStack(stack)).toMatchSnapshot();
 });
diff --git a/test/monitoring/aws-glue/__snapshots__/GlueJobMonitoring.test.ts.snap b/test/monitoring/aws-glue/__snapshots__/GlueJobMonitoring.test.ts.snap
index dd795fe5..f05bd763 100644
--- a/test/monitoring/aws-glue/__snapshots__/GlueJobMonitoring.test.ts.snap
+++ b/test/monitoring/aws-glue/__snapshots__/GlueJobMonitoring.test.ts.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`snapshot test 1`] = `
+exports[`snapshot test: all alarms 1`] = `
 Object {
   "Parameters": Object {
     "BootstrapVersion": Object {
@@ -9,6 +9,388 @@ Object {
       "Type": "AWS::SSM::Parameter::Value<String>",
     },
   },
+  "Resources": Object {
+    "Alarm7103F465": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"widgets\\":[{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+              Object {
+                "Fn::GetAtt": Array [
+                  "ScopeTestDummyApiFaultCountWarning6270BEC0",
+                  "Arn",
+                ],
+              },
+              "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":6,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+              Object {
+                "Fn::GetAtt": Array [
+                  "ScopeTestDummyApiFaultRateWarning63CFB7F0",
+                  "Arn",
+                ],
+              },
+              "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":12,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+              Object {
+                "Fn::GetAtt": Array [
+                  "ScopeTestDummyApiKilledCountWarningCA57B7AE",
+                  "Arn",
+                ],
+              },
+              "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":18,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+              Object {
+                "Fn::GetAtt": Array [
+                  "ScopeTestDummyApiKilledRateWarningA1341942",
+                  "Arn",
+                ],
+              },
+              "\\"]},\\"yAxis\\":{}}}]}",
+            ],
+          ],
+        },
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "Resource": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Glue Job **DummyGlueJob**\\"}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Job Execution\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberAllExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Active Executors\\"}],[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Maximum Needed Executors\\",\\"stat\\":\\"Maximum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numCompletedStages\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Completed Stages\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":6,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Data Movement\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.s3.filesystem.read_bytes\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Read (S3)\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.ALL.s3.filesystem.write_bytes\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Write (S3)\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"bytes\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Memory Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":18,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Failed > 3 for 3 datapoints within 15 minutes\\",\\"value\\":3,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Killed > 3 for 3 datapoints within 15 minutes\\",\\"value\\":3,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":21,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Failed Tasks (avg) > 4 for 3 datapoints within 15 minutes\\",\\"value\\":4,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Killed Tasks (avg) > 2 for 3 datapoints within 15 minutes\\",\\"value\\":2,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "ScopeTestDummyApiFaultCountWarning6270BEC0": Object {
+      "Properties": Object {
+        "ActionsEnabled": true,
+        "AlarmDescription": "Fault count is too high.",
+        "AlarmName": "Test-DummyApi-Fault-Count-Warning",
+        "ComparisonOperator": "GreaterThanThreshold",
+        "DatapointsToAlarm": 3,
+        "EvaluationPeriods": 3,
+        "Metrics": Array [
+          Object {
+            "Id": "m1",
+            "Label": "Failed",
+            "MetricStat": Object {
+              "Metric": Object {
+                "Dimensions": Array [
+                  Object {
+                    "Name": "JobName",
+                    "Value": "DummyGlueJob",
+                  },
+                  Object {
+                    "Name": "JobRunId",
+                    "Value": "ALL",
+                  },
+                  Object {
+                    "Name": "Type",
+                    "Value": "gauge",
+                  },
+                ],
+                "MetricName": "glue.driver.aggregate.numFailedTasks",
+                "Namespace": "Glue",
+              },
+              "Period": 300,
+              "Stat": "Sum",
+            },
+            "ReturnData": true,
+          },
+        ],
+        "Threshold": 3,
+        "TreatMissingData": "notBreaching",
+      },
+      "Type": "AWS::CloudWatch::Alarm",
+    },
+    "ScopeTestDummyApiFaultRateWarning63CFB7F0": Object {
+      "Properties": Object {
+        "ActionsEnabled": true,
+        "AlarmDescription": "Fault rate is too high.",
+        "AlarmName": "Test-DummyApi-Fault-Rate-Warning",
+        "ComparisonOperator": "GreaterThanThreshold",
+        "DatapointsToAlarm": 3,
+        "EvaluationPeriods": 3,
+        "Metrics": Array [
+          Object {
+            "Id": "m1",
+            "Label": "Failed Tasks (avg)",
+            "MetricStat": Object {
+              "Metric": Object {
+                "Dimensions": Array [
+                  Object {
+                    "Name": "JobName",
+                    "Value": "DummyGlueJob",
+                  },
+                  Object {
+                    "Name": "JobRunId",
+                    "Value": "ALL",
+                  },
+                  Object {
+                    "Name": "Type",
+                    "Value": "gauge",
+                  },
+                ],
+                "MetricName": "glue.driver.aggregate.numFailedTasks",
+                "Namespace": "Glue",
+              },
+              "Period": 300,
+              "Stat": "Average",
+            },
+            "ReturnData": true,
+          },
+        ],
+        "Threshold": 4,
+        "TreatMissingData": "notBreaching",
+      },
+      "Type": "AWS::CloudWatch::Alarm",
+    },
+    "ScopeTestDummyApiKilledCountWarningCA57B7AE": Object {
+      "Properties": Object {
+        "ActionsEnabled": true,
+        "AlarmDescription": "Killed count is too high.",
+        "AlarmName": "Test-DummyApi-Killed-Count-Warning",
+        "ComparisonOperator": "GreaterThanThreshold",
+        "DatapointsToAlarm": 3,
+        "EvaluationPeriods": 3,
+        "Metrics": Array [
+          Object {
+            "Id": "m1",
+            "Label": "Killed",
+            "MetricStat": Object {
+              "Metric": Object {
+                "Dimensions": Array [
+                  Object {
+                    "Name": "JobName",
+                    "Value": "DummyGlueJob",
+                  },
+                  Object {
+                    "Name": "JobRunId",
+                    "Value": "ALL",
+                  },
+                  Object {
+                    "Name": "Type",
+                    "Value": "gauge",
+                  },
+                ],
+                "MetricName": "glue.driver.aggregate.numKilledTasks",
+                "Namespace": "Glue",
+              },
+              "Period": 300,
+              "Stat": "Sum",
+            },
+            "ReturnData": true,
+          },
+        ],
+        "Threshold": 3,
+        "TreatMissingData": "notBreaching",
+      },
+      "Type": "AWS::CloudWatch::Alarm",
+    },
+    "ScopeTestDummyApiKilledRateWarningA1341942": Object {
+      "Properties": Object {
+        "ActionsEnabled": true,
+        "AlarmDescription": "Killed rate is too high.",
+        "AlarmName": "Test-DummyApi-Killed-Rate-Warning",
+        "ComparisonOperator": "GreaterThanThreshold",
+        "DatapointsToAlarm": 3,
+        "EvaluationPeriods": 3,
+        "Metrics": Array [
+          Object {
+            "Id": "m1",
+            "Label": "Killed Tasks (avg)",
+            "MetricStat": Object {
+              "Metric": Object {
+                "Dimensions": Array [
+                  Object {
+                    "Name": "JobName",
+                    "Value": "DummyGlueJob",
+                  },
+                  Object {
+                    "Name": "JobRunId",
+                    "Value": "ALL",
+                  },
+                  Object {
+                    "Name": "Type",
+                    "Value": "gauge",
+                  },
+                ],
+                "MetricName": "glue.driver.aggregate.numKilledTasks",
+                "Namespace": "Glue",
+              },
+              "Period": 300,
+              "Stat": "Average",
+            },
+            "ReturnData": true,
+          },
+        ],
+        "Threshold": 2,
+        "TreatMissingData": "notBreaching",
+      },
+      "Type": "AWS::CloudWatch::Alarm",
+    },
+    "Summary68521F81": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Glue Job **DummyGlueJob**\\"}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Job Execution\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberAllExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Active Executors\\"}],[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Maximum Needed Executors\\",\\"stat\\":\\"Maximum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numCompletedStages\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Completed Stages\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Memory Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+  },
+  "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.",
+        },
+      ],
+    },
+  },
+}
+`;
+
+exports[`snapshot test: no alarms 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 {
+    "Alarm7103F465": Object {
+      "Properties": Object {
+        "DashboardBody": "{\\"widgets\\":[]}",
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "Resource": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Glue Job **DummyGlueJob**\\"}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Job Execution\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberAllExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Active Executors\\"}],[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Maximum Needed Executors\\",\\"stat\\":\\"Maximum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numCompletedStages\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Completed Stages\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":6,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Data Movement\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.s3.filesystem.read_bytes\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Read (S3)\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.ALL.s3.filesystem.write_bytes\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Write (S3)\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"bytes\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Memory Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":18,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed\\",\\"stat\\":\\"Sum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":3,\\"height\\":5,\\"x\\":21,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.aggregate.numFailedTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Failed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numKilledTasks\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Killed Tasks (avg) (min: \${MIN}, max: \${MAX})\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+    "Summary68521F81": Object {
+      "Properties": Object {
+        "DashboardBody": Object {
+          "Fn::Join": Array [
+            "",
+            Array [
+              "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### Glue Job **DummyGlueJob**\\"}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Job Execution\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberAllExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Active Executors\\"}],[\\"Glue\\",\\"glue.driver.ExecutorAllocationManager.executors.numberMaxNeededExecutors\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Maximum Needed Executors\\",\\"stat\\":\\"Maximum\\"}],[\\"Glue\\",\\"glue.driver.aggregate.numCompletedStages\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Completed Stages\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Memory Usage\\",\\"region\\":\\"",
+              Object {
+                "Ref": "AWS::Region",
+              },
+              "\\",\\"metrics\\":[[\\"Glue\\",\\"glue.ALL.system.cpuSystemLoad\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"CPU\\"}],[\\"Glue\\",\\"glue.ALL.jvm.heap.usage\\",\\"JobName\\",\\"DummyGlueJob\\",\\"JobRunId\\",\\"ALL\\",\\"Type\\",\\"gauge\\",{\\"label\\":\\"Heap\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}}]}",
+            ],
+          ],
+        },
+      },
+      "Type": "AWS::CloudWatch::Dashboard",
+    },
+  },
   "Rules": Object {
     "CheckBootstrapVersion": Object {
       "Assertions": Array [