From 90021228eb09936f59036ead1a627a6a9a6b53ea Mon Sep 17 00:00:00 2001
From: Mitchell-Cook <109987577+Mitchell-Cook@users.noreply.github.com>
Date: Fri, 27 Jan 2023 12:36:27 -0800
Subject: [PATCH] feat(alarm): Make AlarmNamingStrategy customizable (#316)
Making the AlarmNamingStrategy configurable. My team wants to add the disambiguator to the alarm dedupe string. This requires custom logic for generating the deduplication string, which is why we want to be able to override this class's functionality.
_By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_
---
API.md | 83 +++++++++++++++++++++++-
lib/common/alarm/AlarmFactory.ts | 22 +++++--
lib/common/alarm/AlarmNamingStrategy.ts | 11 +---
lib/common/alarm/IAlarmNamingStrategy.ts | 31 +++++++++
lib/common/alarm/index.ts | 1 +
test/common/alarm/AlarmFactory.test.ts | 32 +++++++++
6 files changed, 164 insertions(+), 16 deletions(-)
create mode 100644 lib/common/alarm/IAlarmNamingStrategy.ts
diff --git a/API.md b/API.md
index 51a48d7a..49ddf56f 100644
--- a/API.md
+++ b/API.md
@@ -2957,6 +2957,7 @@ const alarmFactoryDefaults: AlarmFactoryDefaults = { ... }
| actionsEnabled
| boolean \| {[ key: string ]: boolean}
| Enables the configured CloudWatch alarm ticketing actions for either all severities, or per severity. |
| alarmNamePrefix
| string
| Global prefix for all alarm names. |
| action
| IAlarmActionStrategy
| Default alarm action used for each alarm, unless it is overridden. |
+| alarmNamingStrategy
| IAlarmNamingStrategy
| Custom strategy to name alarms. |
| annotationStrategy
| IAlarmAnnotationStrategy
| Custom strategy to create annotations for alarms. |
| datapointsToAlarm
| number
| Number of breaches required to transition into an ALARM state. |
| dedupeStringProcessor
| IAlarmDedupeStringProcessor
| Custom strategy to process dedupe strings of the alarms. |
@@ -3009,6 +3010,19 @@ Default alarm action used for each alarm, unless it is overridden.
---
+##### `alarmNamingStrategy`Optional
+
+```typescript
+public readonly alarmNamingStrategy: IAlarmNamingStrategy;
+```
+
+- *Type:* IAlarmNamingStrategy
+- *Default:* default behaviour (no change)
+
+Custom strategy to name alarms.
+
+---
+
##### `annotationStrategy`Optional
```typescript
@@ -38150,6 +38164,8 @@ Any warnings that are produced as a result of putting together this widget.
### AlarmNamingStrategy
+- *Implements:* IAlarmNamingStrategy
+
#### Initializers
```typescript
@@ -38190,7 +38206,7 @@ new AlarmNamingStrategy(globalPrefix: string, localPrefix: string, dedupeStringS
| --- | --- |
| getDedupeString
| Dedupe string resolved like this: - If "dedupeStringOverride" is defined for an alarm, it will be used as a dedupe string. |
| getName
| Alarm name is resolved like this: - If "alarmNameOverride" is defined for an alarm, it will be used as alarm name. |
-| getWidgetLabel
| *No description.* |
+| getWidgetLabel
| How to generate the label for the alarm displayed on a widget. |
---
@@ -38238,6 +38254,8 @@ properties.
public getWidgetLabel(props: AlarmNamingInput): string
```
+How to generate the label for the alarm displayed on a widget.
+
###### `props`Required
- *Type:* AlarmNamingInput
@@ -60516,6 +60534,69 @@ Process the dedupe string which was specified by the user as an override.
---
+### IAlarmNamingStrategy
+
+- *Implemented By:* AlarmNamingStrategy, IAlarmNamingStrategy
+
+Strategy used to name alarms, their widgets, and their dedupe strings.
+
+#### Methods
+
+| **Name** | **Description** |
+| --- | --- |
+| getDedupeString
| How to generate the deduplication string for an alarm. |
+| getName
| How to generate the name of an alarm. |
+| getWidgetLabel
| How to generate the label for the alarm displayed on a widget. |
+
+---
+
+##### `getDedupeString`
+
+```typescript
+public getDedupeString(props: AlarmNamingInput): string
+```
+
+How to generate the deduplication string for an alarm.
+
+###### `props`Required
+
+- *Type:* AlarmNamingInput
+
+---
+
+##### `getName`
+
+```typescript
+public getName(props: AlarmNamingInput): string
+```
+
+How to generate the name of an alarm.
+
+###### `props`Required
+
+- *Type:* AlarmNamingInput
+
+AlarmNamingInput.
+
+---
+
+##### `getWidgetLabel`
+
+```typescript
+public getWidgetLabel(props: AlarmNamingInput): string
+```
+
+How to generate the label for the alarm displayed on a widget.
+
+###### `props`Required
+
+- *Type:* AlarmNamingInput
+
+AlarmNamingInput.
+
+---
+
+
### IDashboardFactory
- *Implemented By:* DefaultDashboardFactory, IDashboardFactory
diff --git a/lib/common/alarm/AlarmFactory.ts b/lib/common/alarm/AlarmFactory.ts
index a763a283..33c57db5 100644
--- a/lib/common/alarm/AlarmFactory.ts
+++ b/lib/common/alarm/AlarmFactory.ts
@@ -19,6 +19,7 @@ import {
IAlarmAnnotationStrategy,
} from "./IAlarmAnnotationStrategy";
import { IAlarmDedupeStringProcessor } from "./IAlarmDedupeStringProcessor";
+import { IAlarmNamingStrategy } from "./IAlarmNamingStrategy";
import { noopAction } from "./NoopAlarmActionStrategy";
import {
MetricFactoryDefaults,
@@ -403,6 +404,13 @@ export interface AlarmFactoryDefaults {
*/
readonly dedupeStringProcessor?: IAlarmDedupeStringProcessor;
+ /**
+ * Custom strategy to name alarms
+ *
+ * @default - default behaviour (no change)
+ */
+ readonly alarmNamingStrategy?: IAlarmNamingStrategy;
+
/**
* Number of breaches required to transition into an ALARM state.
*
@@ -460,17 +468,19 @@ export class AlarmFactory {
protected readonly alarmScope: Construct;
protected readonly globalAlarmDefaults: AlarmFactoryDefaults;
protected readonly globalMetricDefaults: MetricFactoryDefaults;
- protected readonly alarmNamingStrategy: AlarmNamingStrategy;
+ protected readonly alarmNamingStrategy: IAlarmNamingStrategy;
constructor(alarmScope: Construct, props: AlarmFactoryProps) {
this.alarmScope = alarmScope;
this.globalAlarmDefaults = props.globalAlarmDefaults;
this.globalMetricDefaults = props.globalMetricDefaults;
- this.alarmNamingStrategy = new AlarmNamingStrategy(
- props.globalAlarmDefaults.alarmNamePrefix,
- props.localAlarmNamePrefix,
- props.globalAlarmDefaults.dedupeStringProcessor
- );
+ this.alarmNamingStrategy =
+ props.globalAlarmDefaults.alarmNamingStrategy ??
+ new AlarmNamingStrategy(
+ props.globalAlarmDefaults.alarmNamePrefix,
+ props.localAlarmNamePrefix,
+ props.globalAlarmDefaults.dedupeStringProcessor
+ );
}
addAlarm(
diff --git a/lib/common/alarm/AlarmNamingStrategy.ts b/lib/common/alarm/AlarmNamingStrategy.ts
index d87cf439..6a66bbe5 100644
--- a/lib/common/alarm/AlarmNamingStrategy.ts
+++ b/lib/common/alarm/AlarmNamingStrategy.ts
@@ -2,19 +2,12 @@ import {
DoNotModifyDedupeString,
IAlarmDedupeStringProcessor,
} from "./IAlarmDedupeStringProcessor";
+import { AlarmNamingInput, IAlarmNamingStrategy } from "./IAlarmNamingStrategy";
const AlarmNamePartSeparator = "-";
const AlarmLabelPartSeparator = " ";
-export interface AlarmNamingInput {
- readonly alarmNameSuffix: string;
- readonly alarmNameOverride?: string;
- readonly alarmDedupeStringSuffix?: string;
- readonly dedupeStringOverride?: string;
- readonly disambiguator?: string;
-}
-
-export class AlarmNamingStrategy {
+export class AlarmNamingStrategy implements IAlarmNamingStrategy {
protected readonly globalPrefix: string;
protected readonly localPrefix: string;
protected readonly dedupeStringStrategy: IAlarmDedupeStringProcessor;
diff --git a/lib/common/alarm/IAlarmNamingStrategy.ts b/lib/common/alarm/IAlarmNamingStrategy.ts
new file mode 100644
index 00000000..61becfaf
--- /dev/null
+++ b/lib/common/alarm/IAlarmNamingStrategy.ts
@@ -0,0 +1,31 @@
+export interface AlarmNamingInput {
+ readonly alarmNameSuffix: string;
+ readonly alarmNameOverride?: string;
+ readonly alarmDedupeStringSuffix?: string;
+ readonly dedupeStringOverride?: string;
+ readonly disambiguator?: string;
+}
+
+/**
+ * Strategy used to name alarms, their widgets, and their dedupe strings.
+ */
+export interface IAlarmNamingStrategy {
+ /**
+ * How to generate the name of an alarm.
+ *
+ * @param props AlarmNamingInput
+ */
+ getName(props: AlarmNamingInput): string;
+
+ /**
+ * How to generate the label for the alarm displayed on a widget.
+ *
+ * @param props AlarmNamingInput
+ */
+ getWidgetLabel(props: AlarmNamingInput): string;
+
+ /**
+ * How to generate the deduplication string for an alarm.
+ */
+ getDedupeString(props: AlarmNamingInput): string | undefined;
+}
diff --git a/lib/common/alarm/index.ts b/lib/common/alarm/index.ts
index 2b79ae9a..b940bbae 100644
--- a/lib/common/alarm/index.ts
+++ b/lib/common/alarm/index.ts
@@ -4,6 +4,7 @@ export * from "./CustomAlarmThreshold";
export * from "./IAlarmActionStrategy";
export * from "./IAlarmAnnotationStrategy";
export * from "./IAlarmDedupeStringProcessor";
+export * from "./IAlarmNamingStrategy";
export * from "./MultipleAlarmActionStrategy";
export * from "./NoopAlarmActionStrategy";
export * from "./OpsItemAlarmActionStrategy";
diff --git a/test/common/alarm/AlarmFactory.test.ts b/test/common/alarm/AlarmFactory.test.ts
index c745dd92..cb53058e 100644
--- a/test/common/alarm/AlarmFactory.test.ts
+++ b/test/common/alarm/AlarmFactory.test.ts
@@ -14,7 +14,9 @@ import {
AddAlarmProps,
AlarmFactory,
AlarmFactoryDefaults,
+ AlarmNamingInput,
CompositeAlarmOperator,
+ IAlarmNamingStrategy,
MetricFactoryDefaults,
multipleActions,
noopAction,
@@ -409,3 +411,33 @@ test("addAlarm: disambigatorAction takes precedence over default action", () =>
expect(alarm.action).toStrictEqual(snsAction);
});
+
+test("addAlarm: custom alarm naming strategy", () => {
+ const alarmName = "alarmName";
+ const alarmLabel = "alarmLabel";
+ const alarmDedupe = "alarmDedupe";
+ const disambiguator = "Critical";
+ const stack = new Stack();
+ const customNamingStrategy: IAlarmNamingStrategy = {
+ getName: (props: AlarmNamingInput) => `${alarmName}-${props.disambiguator}`,
+ getWidgetLabel: (props: AlarmNamingInput) =>
+ `${alarmLabel}-${props.disambiguator}`,
+ getDedupeString: (props: AlarmNamingInput) =>
+ `${alarmDedupe}-${props.disambiguator}`,
+ };
+ const factory = new AlarmFactory(stack, {
+ globalMetricDefaults,
+ globalAlarmDefaults: {
+ ...globalAlarmDefaultsWithDisambiguator,
+ alarmNamingStrategy: customNamingStrategy,
+ },
+ localAlarmNamePrefix: "prefix",
+ });
+ const alarm = factory.addAlarm(metric, {
+ ...props,
+ disambiguator,
+ });
+ expect(alarm.alarmName).toBe(`${alarmName}-${disambiguator}`);
+ expect(alarm.alarmLabel).toBe(`${alarmLabel}-${disambiguator}`);
+ expect(alarm.dedupeString).toBe(`${alarmDedupe}-${disambiguator}`);
+});