@guardian/cdk 50.10.7 → 50.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,2 @@
1
- export * from "./error-budget-alarm";
2
1
  export * from "./root";
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/constructs/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/experimental/constructs/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC"}
@@ -14,6 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./error-budget-alarm"), exports);
18
17
  __exportStar(require("./root"), exports);
19
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/experimental/constructs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,yCAAuB","sourcesContent":["export * from \"./error-budget-alarm\";\nexport * from \"./root\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/experimental/constructs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB","sourcesContent":["export * from \"./root\";\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@guardian/cdk",
3
3
  "description": "Generic Guardian flavoured AWS CDK components",
4
- "version": "50.10.7",
4
+ "version": "50.10.9",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "files": [
@@ -36,15 +36,15 @@
36
36
  "@types/lodash.camelcase": "^4.3.7",
37
37
  "@types/lodash.kebabcase": "^4.1.7",
38
38
  "@types/lodash.upperfirst": "^4.3.7",
39
- "@types/node": "20.4.5",
39
+ "@types/node": "20.4.9",
40
40
  "@types/yargs": "^17.0.19",
41
41
  "aws-cdk": "2.90.0",
42
42
  "cz-conventional-changelog": "^3.3.0",
43
- "eslint": "^8.46.0",
43
+ "eslint": "^8.47.0",
44
44
  "eslint-plugin-custom-rules": "file:tools/eslint",
45
- "gh-pages": "^5.0.0",
45
+ "gh-pages": "^6.0.0",
46
46
  "jest": "^29.6.2",
47
- "prettier": "^3.0.0",
47
+ "prettier": "^3.0.2",
48
48
  "semantic-release": "^21.0.7",
49
49
  "serve": "^14.2.0",
50
50
  "ts-jest": "^29.1.1",
@@ -53,11 +53,11 @@
53
53
  "typescript": "~4.9.5"
54
54
  },
55
55
  "dependencies": {
56
- "@oclif/core": "2.11.5",
56
+ "@oclif/core": "2.11.8",
57
57
  "aws-cdk-lib": "2.90.0",
58
- "aws-sdk": "^2.1427.0",
58
+ "aws-sdk": "^2.1437.0",
59
59
  "chalk": "^4.1.2",
60
- "codemaker": "^1.86.0",
60
+ "codemaker": "^1.87.0",
61
61
  "constructs": "10.2.69",
62
62
  "git-url-parse": "^13.1.0",
63
63
  "js-yaml": "^4.1.0",
@@ -1,57 +0,0 @@
1
- import type { IMetric } from "aws-cdk-lib/aws-cloudwatch";
2
- import { Construct } from "constructs";
3
- import type { GuStack } from "../../constructs/core";
4
- export interface ErrorBudgetAlarmProps {
5
- /**
6
- * The name of the SLO. Assumed to be unique per stack.
7
- */
8
- sloName: string;
9
- /**
10
- * The percentange target for the SLO, expressed as a decimal floating point number. Must be between 0.95 and 0.995.
11
- */
12
- sloTarget: number;
13
- /**
14
- * The metric representing the bad events. Can be any IMetric type, like Metric or MathExpression.
15
- */
16
- badEvents: IMetric;
17
- /**
18
- * The metric representing the events to be considered. Can be any IMetric type, like Metric or MathExpression.
19
- */
20
- validEvents: IMetric;
21
- /**
22
- * The sns topic name (not the full arn) used by the alarm to send email alerts.
23
- */
24
- snsTopicNameForAlerts: string;
25
- }
26
- /**
27
- * Use this construct to create alarms that will notify you when you are at risk of missing your SLO targets.
28
- *
29
- * These alarms follow the recommendations in the [SRE Workbook](https://sre.google/workbook/alerting-on-slos/) to
30
- * implement Multiwindow, Multi-Burn-Rate Alerts.
31
- *
32
- * The CloudWatch implementation of this strategy creates nine separate CloudWatch alarms. The main alarms that users
33
- * need to care about are the three composite alarms. These track different burn rates of error budget consumption:
34
- * fast (e.g. complete outages), medium (e.g. moderate error percentage over hours, rather than minutes) and slow (e.g.
35
- * a small percentage of errors sustained over a much longer period). Multiple burn rates are used to ensure that
36
- * we are able to pick up all scenarios which could threaten the SLO, without interrupting developers with an
37
- * unnecessary level of urgency.
38
- *
39
- * Each composite alarm creates two child alarms; these are used to support multiple windows (or periods in CloudWatch
40
- * terminology). A composite alarm is configured to send notifications if both of its child alarms are in an alarm state.
41
- * The child alarms themselves have no actions/notifications configured and users should not need to interact with them
42
- * directly. Multiple windows are helpful for accuracy and reset time. The long window helps us to avoid sending an
43
- * alert in scenarios where no intervention is required, for example a very brief spike in errors that is resolved
44
- * automatically (e.g. when AWS replaces a 'bad' EC2 instance). The short window helps to ensure that the alert is reset
45
- * (or moved back into OK state, in CloudWatch terminology) promptly once a problem has been resolved.
46
- *
47
- * The composite alarms have an awareness of priority, meaning that low priority alarm notifications are suppressed if
48
- * a higher priority alarm is already firing. That is, if you receive an alert about fast error budget consumption, you
49
- * should not receive an alert from the medium or slow versions of the alarm.
50
- *
51
- * For how to instantiate an ErrorBudgetAlarm check the unit-test in error-budget-alarm.test.ts,
52
- * and for a description of the props that need to be passed see [[ErrorBudgetAlarmProps]]
53
- */
54
- export declare class GuErrorBudgetAlarmExperimental extends Construct {
55
- constructor(scope: GuStack, props: ErrorBudgetAlarmProps);
56
- }
57
- //# sourceMappingURL=error-budget-alarm.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-budget-alarm.d.ts","sourceRoot":"","sources":["../../../src/experimental/constructs/error-budget-alarm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAa7E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,8BAA+B,SAAQ,SAAS;gBAC/C,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB;CAsEzD"}
@@ -1,148 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GuErrorBudgetAlarmExperimental = void 0;
4
- const aws_cdk_lib_1 = require("aws-cdk-lib");
5
- const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
6
- const aws_cloudwatch_actions_1 = require("aws-cdk-lib/aws-cloudwatch-actions");
7
- const aws_sns_1 = require("aws-cdk-lib/aws-sns");
8
- const constructs_1 = require("constructs");
9
- /**
10
- * Use this construct to create alarms that will notify you when you are at risk of missing your SLO targets.
11
- *
12
- * These alarms follow the recommendations in the [SRE Workbook](https://sre.google/workbook/alerting-on-slos/) to
13
- * implement Multiwindow, Multi-Burn-Rate Alerts.
14
- *
15
- * The CloudWatch implementation of this strategy creates nine separate CloudWatch alarms. The main alarms that users
16
- * need to care about are the three composite alarms. These track different burn rates of error budget consumption:
17
- * fast (e.g. complete outages), medium (e.g. moderate error percentage over hours, rather than minutes) and slow (e.g.
18
- * a small percentage of errors sustained over a much longer period). Multiple burn rates are used to ensure that
19
- * we are able to pick up all scenarios which could threaten the SLO, without interrupting developers with an
20
- * unnecessary level of urgency.
21
- *
22
- * Each composite alarm creates two child alarms; these are used to support multiple windows (or periods in CloudWatch
23
- * terminology). A composite alarm is configured to send notifications if both of its child alarms are in an alarm state.
24
- * The child alarms themselves have no actions/notifications configured and users should not need to interact with them
25
- * directly. Multiple windows are helpful for accuracy and reset time. The long window helps us to avoid sending an
26
- * alert in scenarios where no intervention is required, for example a very brief spike in errors that is resolved
27
- * automatically (e.g. when AWS replaces a 'bad' EC2 instance). The short window helps to ensure that the alert is reset
28
- * (or moved back into OK state, in CloudWatch terminology) promptly once a problem has been resolved.
29
- *
30
- * The composite alarms have an awareness of priority, meaning that low priority alarm notifications are suppressed if
31
- * a higher priority alarm is already firing. That is, if you receive an alert about fast error budget consumption, you
32
- * should not receive an alert from the medium or slow versions of the alarm.
33
- *
34
- * For how to instantiate an ErrorBudgetAlarm check the unit-test in error-budget-alarm.test.ts,
35
- * and for a description of the props that need to be passed see [[ErrorBudgetAlarmProps]]
36
- */
37
- class GuErrorBudgetAlarmExperimental extends constructs_1.Construct {
38
- constructor(scope, props) {
39
- const lowestTargetAllowed = 0.95;
40
- const highestTargetAllowed = 0.9995;
41
- if (!(props.sloTarget >= lowestTargetAllowed && props.sloTarget <= highestTargetAllowed)) {
42
- throw new Error(`ErrorBudgetAlarm only works with SLO targets between ${lowestTargetAllowed} and ${highestTargetAllowed}`);
43
- }
44
- super(scope, props.sloName); // The assumption here is that `sloName` will be unique (per stack)
45
- const errorBudget = 1 - props.sloTarget;
46
- const snsTopic = aws_sns_1.Topic.fromTopicArn(scope, `SnsSloAlarmsFor${props.sloName}`, `arn:aws:sns:${scope.region}:${scope.account}:${props.snsTopicNameForAlerts}`);
47
- const fastBurnRate = {
48
- speed: "Fast",
49
- burnRate: 14.4,
50
- longPeriod: aws_cdk_lib_1.Duration.hours(1),
51
- shortPeriod: aws_cdk_lib_1.Duration.minutes(5),
52
- };
53
- const fastBurnAlarm = new CompositeBurnRateAlarm(scope, {
54
- sloName: props.sloName,
55
- badEvents: props.badEvents,
56
- burnRateMonitoring: fastBurnRate,
57
- errorBudget,
58
- snsTopic,
59
- validEvents: props.validEvents,
60
- });
61
- const mediumBurnRateMonitoring = {
62
- speed: "Medium",
63
- burnRate: 6,
64
- longPeriod: aws_cdk_lib_1.Duration.hours(6),
65
- shortPeriod: aws_cdk_lib_1.Duration.minutes(30),
66
- };
67
- const mediumBurnRateAlarm = new CompositeBurnRateAlarm(scope, {
68
- sloName: props.sloName,
69
- badEvents: props.badEvents,
70
- burnRateMonitoring: mediumBurnRateMonitoring,
71
- errorBudget,
72
- snsTopic,
73
- validEvents: props.validEvents,
74
- suppressorAlarm: fastBurnAlarm,
75
- });
76
- const slowBurnRate = {
77
- speed: "Slow",
78
- burnRate: 3,
79
- longPeriod: aws_cdk_lib_1.Duration.days(1),
80
- shortPeriod: aws_cdk_lib_1.Duration.hours(2),
81
- };
82
- new CompositeBurnRateAlarm(scope, {
83
- sloName: props.sloName,
84
- badEvents: props.badEvents,
85
- burnRateMonitoring: slowBurnRate,
86
- errorBudget,
87
- // TODO - use a different topic for tickets or figure out how to route notifications vs tickets using a single topic
88
- snsTopic,
89
- validEvents: props.validEvents,
90
- suppressorAlarm: mediumBurnRateAlarm,
91
- });
92
- }
93
- }
94
- exports.GuErrorBudgetAlarmExperimental = GuErrorBudgetAlarmExperimental;
95
- class MonitorBurnRateForPeriod extends aws_cloudwatch_1.Alarm {
96
- constructor(scope, props) {
97
- const undesirableErrorBudgetConsumption = props.errorBudget * props.burnRateSpeed.burnRate;
98
- super(scope, props.alarmName, {
99
- alarmName: props.alarmName,
100
- metric: new aws_cloudwatch_1.MathExpression({
101
- expression: "badEvents/validEvents",
102
- label: "Observed failure rate",
103
- usingMetrics: {
104
- badEvents: props.badEvents,
105
- validEvents: props.validEvents,
106
- },
107
- period: props.period,
108
- }),
109
- evaluationPeriods: 1,
110
- threshold: undesirableErrorBudgetConsumption,
111
- comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
112
- treatMissingData: aws_cloudwatch_1.TreatMissingData.NOT_BREACHING,
113
- });
114
- }
115
- }
116
- class CompositeBurnRateAlarm extends aws_cloudwatch_1.CompositeAlarm {
117
- constructor(scope, props) {
118
- const alarmName = `${props.sloName}${props.burnRateMonitoring.speed}BurnCompositeAlarm`;
119
- const sharedIndividualAlarmProps = {
120
- badEvents: props.badEvents,
121
- burnRateSpeed: {
122
- speed: props.burnRateMonitoring.speed,
123
- burnRate: props.burnRateMonitoring.burnRate,
124
- },
125
- errorBudget: props.errorBudget,
126
- validEvents: props.validEvents,
127
- };
128
- super(scope, alarmName, {
129
- alarmRule: aws_cloudwatch_1.AlarmRule.allOf(aws_cloudwatch_1.AlarmRule.fromAlarm(new MonitorBurnRateForPeriod(scope, {
130
- ...sharedIndividualAlarmProps,
131
- alarmName: `ChildAlarmLongPeriod${alarmName}`,
132
- period: props.burnRateMonitoring.longPeriod,
133
- }), aws_cloudwatch_1.AlarmState.ALARM), aws_cloudwatch_1.AlarmRule.fromAlarm(new MonitorBurnRateForPeriod(scope, {
134
- ...sharedIndividualAlarmProps,
135
- alarmName: `ChildAlarmShortPeriod${alarmName}`,
136
- period: props.burnRateMonitoring.shortPeriod,
137
- }), aws_cloudwatch_1.AlarmState.ALARM)),
138
- });
139
- this.addAlarmAction(new aws_cloudwatch_actions_1.SnsAction(props.snsTopic));
140
- if (props.suppressorAlarm) {
141
- const cfnAlarm = this.node.defaultChild;
142
- cfnAlarm.actionsSuppressor = props.suppressorAlarm.alarmArn;
143
- cfnAlarm.actionsSuppressorWaitPeriod = 120;
144
- cfnAlarm.actionsSuppressorExtensionPeriod = props.burnRateMonitoring.shortPeriod.toSeconds();
145
- }
146
- }
147
- }
148
- //# sourceMappingURL=error-budget-alarm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-budget-alarm.js","sourceRoot":"","sources":["../../../src/experimental/constructs/error-budget-alarm.ts"],"names":[],"mappings":";;;AAAA,6CAAuC;AAEvC,+DAQoC;AACpC,+EAA+D;AAE/D,iDAA4C;AAC5C,2CAAuC;AAuDvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAa,8BAA+B,SAAQ,sBAAS;IAC3D,YAAY,KAAc,EAAE,KAA4B;QACtD,MAAM,mBAAmB,GAAG,IAAI,CAAC;QACjC,MAAM,oBAAoB,GAAG,MAAM,CAAC;QACpC,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,mBAAmB,IAAI,KAAK,CAAC,SAAS,IAAI,oBAAoB,CAAC,EAAE;YACxF,MAAM,IAAI,KAAK,CACb,wDAAwD,mBAAmB,QAAQ,oBAAoB,EAAE,CAC1G,CAAC;SACH;QAED,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mEAAmE;QAEhG,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;QAExC,MAAM,QAAQ,GAAW,eAAK,CAAC,YAAY,CACzC,KAAK,EACL,kBAAkB,KAAK,CAAC,OAAO,EAAE,EACjC,eAAe,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,qBAAqB,EAAE,CAC9E,CAAC;QAEF,MAAM,YAAY,GAAuB;YACvC,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,sBAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7B,WAAW,EAAE,sBAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;SACjC,CAAC;QAEF,MAAM,aAAa,GAAG,IAAI,sBAAsB,CAAC,KAAK,EAAE;YACtD,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,kBAAkB,EAAE,YAAY;YAChC,WAAW;YACX,QAAQ;YACR,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;QAEH,MAAM,wBAAwB,GAAuB;YACnD,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,sBAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7B,WAAW,EAAE,sBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;SAClC,CAAC;QAEF,MAAM,mBAAmB,GAAG,IAAI,sBAAsB,CAAC,KAAK,EAAE;YAC5D,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,kBAAkB,EAAE,wBAAwB;YAC5C,WAAW;YACX,QAAQ;YACR,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,eAAe,EAAE,aAAa;SAC/B,CAAC,CAAC;QAEH,MAAM,YAAY,GAAuB;YACvC,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,sBAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,WAAW,EAAE,sBAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;SAC/B,CAAC;QAEF,IAAI,sBAAsB,CAAC,KAAK,EAAE;YAChC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,kBAAkB,EAAE,YAAY;YAChC,WAAW;YACX,oHAAoH;YACpH,QAAQ;YACR,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,eAAe,EAAE,mBAAmB;SACrC,CAAC,CAAC;IACL,CAAC;CACF;AAvED,wEAuEC;AAED,MAAM,wBAAyB,SAAQ,sBAAK;IAC1C,YAAY,KAAc,EAAE,KAAoC;QAC9D,MAAM,iCAAiC,GAAG,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC;QAC3F,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,IAAI,+BAAc,CAAC;gBACzB,UAAU,EAAE,uBAAuB;gBACnC,KAAK,EAAE,uBAAuB;gBAC9B,YAAY,EAAE;oBACZ,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;iBAC/B;gBACD,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC;YACF,iBAAiB,EAAE,CAAC;YACpB,SAAS,EAAE,iCAAiC;YAC5C,kBAAkB,EAAE,mCAAkB,CAAC,sBAAsB;YAC7D,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;SACjD,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,sBAAuB,SAAQ,+BAAc;IACjD,YAAY,KAAc,EAAE,KAAkC;QAC5D,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,kBAAkB,CAAC,KAAK,oBAAoB,CAAC;QACxF,MAAM,0BAA0B,GAAG;YACjC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,aAAa,EAAE;gBACb,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,KAAK;gBACrC,QAAQ,EAAE,KAAK,CAAC,kBAAkB,CAAC,QAAQ;aAC5C;YACD,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC;QACF,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE;YACtB,SAAS,EAAE,0BAAS,CAAC,KAAK,CACxB,0BAAS,CAAC,SAAS,CACjB,IAAI,wBAAwB,CAAC,KAAK,EAAE;gBAClC,GAAG,0BAA0B;gBAC7B,SAAS,EAAE,uBAAuB,SAAS,EAAE;gBAC7C,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,UAAU;aAC5C,CAAC,EACF,2BAAU,CAAC,KAAK,CACjB,EACD,0BAAS,CAAC,SAAS,CACjB,IAAI,wBAAwB,CAAC,KAAK,EAAE;gBAClC,GAAG,0BAA0B;gBAC7B,SAAS,EAAE,wBAAwB,SAAS,EAAE;gBAC9C,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,WAAW;aAC7C,CAAC,EACF,2BAAU,CAAC,KAAK,CACjB,CACF;SACF,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,IAAI,kCAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnD,IAAI,KAAK,CAAC,eAAe,EAAE;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAiC,CAAC;YAC7D,QAAQ,CAAC,iBAAiB,GAAG,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC;YAC5D,QAAQ,CAAC,2BAA2B,GAAG,GAAG,CAAC;YAC3C,QAAQ,CAAC,gCAAgC,GAAG,KAAK,CAAC,kBAAkB,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;SAC9F;IACH,CAAC;CACF","sourcesContent":["import { Duration } from \"aws-cdk-lib\";\nimport type { CfnCompositeAlarm, IMetric } from \"aws-cdk-lib/aws-cloudwatch\";\nimport {\n Alarm,\n AlarmRule,\n AlarmState,\n ComparisonOperator,\n CompositeAlarm,\n MathExpression,\n TreatMissingData,\n} from \"aws-cdk-lib/aws-cloudwatch\";\nimport { SnsAction } from \"aws-cdk-lib/aws-cloudwatch-actions\";\nimport type { ITopic } from \"aws-cdk-lib/aws-sns\";\nimport { Topic } from \"aws-cdk-lib/aws-sns\";\nimport { Construct } from \"constructs\";\nimport type { GuStack } from \"../../constructs/core\";\n\nexport interface ErrorBudgetAlarmProps {\n /**\n * The name of the SLO. Assumed to be unique per stack.\n */\n sloName: string;\n /**\n * The percentange target for the SLO, expressed as a decimal floating point number. Must be between 0.95 and 0.995.\n */\n sloTarget: number;\n /**\n * The metric representing the bad events. Can be any IMetric type, like Metric or MathExpression.\n */\n badEvents: IMetric;\n /**\n * The metric representing the events to be considered. Can be any IMetric type, like Metric or MathExpression.\n */\n validEvents: IMetric;\n /**\n * The sns topic name (not the full arn) used by the alarm to send email alerts.\n */\n snsTopicNameForAlerts: string;\n}\n\ninterface BurnRate {\n speed: \"Fast\" | \"Medium\" | \"Slow\";\n burnRate: number;\n}\n\ninterface BurnRateMonitoring extends BurnRate {\n longPeriod: Duration;\n shortPeriod: Duration;\n}\n\ninterface MonitorBurnRateForPeriodProps {\n alarmName: string;\n burnRateSpeed: BurnRate;\n period: Duration;\n errorBudget: number;\n badEvents: IMetric;\n validEvents: IMetric;\n}\n\ninterface CompositeBurnRateAlarmProps {\n sloName: string;\n burnRateMonitoring: BurnRateMonitoring;\n errorBudget: number;\n badEvents: IMetric;\n validEvents: IMetric;\n snsTopic: ITopic;\n suppressorAlarm?: CompositeBurnRateAlarm;\n}\n\n/**\n * Use this construct to create alarms that will notify you when you are at risk of missing your SLO targets.\n *\n * These alarms follow the recommendations in the [SRE Workbook](https://sre.google/workbook/alerting-on-slos/) to\n * implement Multiwindow, Multi-Burn-Rate Alerts.\n *\n * The CloudWatch implementation of this strategy creates nine separate CloudWatch alarms. The main alarms that users\n * need to care about are the three composite alarms. These track different burn rates of error budget consumption:\n * fast (e.g. complete outages), medium (e.g. moderate error percentage over hours, rather than minutes) and slow (e.g.\n * a small percentage of errors sustained over a much longer period). Multiple burn rates are used to ensure that\n * we are able to pick up all scenarios which could threaten the SLO, without interrupting developers with an\n * unnecessary level of urgency.\n *\n * Each composite alarm creates two child alarms; these are used to support multiple windows (or periods in CloudWatch\n * terminology). A composite alarm is configured to send notifications if both of its child alarms are in an alarm state.\n * The child alarms themselves have no actions/notifications configured and users should not need to interact with them\n * directly. Multiple windows are helpful for accuracy and reset time. The long window helps us to avoid sending an\n * alert in scenarios where no intervention is required, for example a very brief spike in errors that is resolved\n * automatically (e.g. when AWS replaces a 'bad' EC2 instance). The short window helps to ensure that the alert is reset\n * (or moved back into OK state, in CloudWatch terminology) promptly once a problem has been resolved.\n *\n * The composite alarms have an awareness of priority, meaning that low priority alarm notifications are suppressed if\n * a higher priority alarm is already firing. That is, if you receive an alert about fast error budget consumption, you\n * should not receive an alert from the medium or slow versions of the alarm.\n *\n * For how to instantiate an ErrorBudgetAlarm check the unit-test in error-budget-alarm.test.ts,\n * and for a description of the props that need to be passed see [[ErrorBudgetAlarmProps]]\n */\nexport class GuErrorBudgetAlarmExperimental extends Construct {\n constructor(scope: GuStack, props: ErrorBudgetAlarmProps) {\n const lowestTargetAllowed = 0.95;\n const highestTargetAllowed = 0.9995;\n if (!(props.sloTarget >= lowestTargetAllowed && props.sloTarget <= highestTargetAllowed)) {\n throw new Error(\n `ErrorBudgetAlarm only works with SLO targets between ${lowestTargetAllowed} and ${highestTargetAllowed}`,\n );\n }\n\n super(scope, props.sloName); // The assumption here is that `sloName` will be unique (per stack)\n\n const errorBudget = 1 - props.sloTarget;\n\n const snsTopic: ITopic = Topic.fromTopicArn(\n scope,\n `SnsSloAlarmsFor${props.sloName}`,\n `arn:aws:sns:${scope.region}:${scope.account}:${props.snsTopicNameForAlerts}`,\n );\n\n const fastBurnRate: BurnRateMonitoring = {\n speed: \"Fast\",\n burnRate: 14.4,\n longPeriod: Duration.hours(1),\n shortPeriod: Duration.minutes(5),\n };\n\n const fastBurnAlarm = new CompositeBurnRateAlarm(scope, {\n sloName: props.sloName,\n badEvents: props.badEvents,\n burnRateMonitoring: fastBurnRate,\n errorBudget,\n snsTopic,\n validEvents: props.validEvents,\n });\n\n const mediumBurnRateMonitoring: BurnRateMonitoring = {\n speed: \"Medium\",\n burnRate: 6,\n longPeriod: Duration.hours(6),\n shortPeriod: Duration.minutes(30),\n };\n\n const mediumBurnRateAlarm = new CompositeBurnRateAlarm(scope, {\n sloName: props.sloName,\n badEvents: props.badEvents,\n burnRateMonitoring: mediumBurnRateMonitoring,\n errorBudget,\n snsTopic,\n validEvents: props.validEvents,\n suppressorAlarm: fastBurnAlarm,\n });\n\n const slowBurnRate: BurnRateMonitoring = {\n speed: \"Slow\",\n burnRate: 3,\n longPeriod: Duration.days(1),\n shortPeriod: Duration.hours(2),\n };\n\n new CompositeBurnRateAlarm(scope, {\n sloName: props.sloName,\n badEvents: props.badEvents,\n burnRateMonitoring: slowBurnRate,\n errorBudget,\n // TODO - use a different topic for tickets or figure out how to route notifications vs tickets using a single topic\n snsTopic,\n validEvents: props.validEvents,\n suppressorAlarm: mediumBurnRateAlarm,\n });\n }\n}\n\nclass MonitorBurnRateForPeriod extends Alarm {\n constructor(scope: GuStack, props: MonitorBurnRateForPeriodProps) {\n const undesirableErrorBudgetConsumption = props.errorBudget * props.burnRateSpeed.burnRate;\n super(scope, props.alarmName, {\n alarmName: props.alarmName,\n metric: new MathExpression({\n expression: \"badEvents/validEvents\",\n label: \"Observed failure rate\",\n usingMetrics: {\n badEvents: props.badEvents,\n validEvents: props.validEvents,\n },\n period: props.period,\n }),\n evaluationPeriods: 1,\n threshold: undesirableErrorBudgetConsumption,\n comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,\n treatMissingData: TreatMissingData.NOT_BREACHING,\n });\n }\n}\n\nclass CompositeBurnRateAlarm extends CompositeAlarm {\n constructor(scope: GuStack, props: CompositeBurnRateAlarmProps) {\n const alarmName = `${props.sloName}${props.burnRateMonitoring.speed}BurnCompositeAlarm`;\n const sharedIndividualAlarmProps = {\n badEvents: props.badEvents,\n burnRateSpeed: {\n speed: props.burnRateMonitoring.speed,\n burnRate: props.burnRateMonitoring.burnRate,\n },\n errorBudget: props.errorBudget,\n validEvents: props.validEvents,\n };\n super(scope, alarmName, {\n alarmRule: AlarmRule.allOf(\n AlarmRule.fromAlarm(\n new MonitorBurnRateForPeriod(scope, {\n ...sharedIndividualAlarmProps,\n alarmName: `ChildAlarmLongPeriod${alarmName}`,\n period: props.burnRateMonitoring.longPeriod,\n }),\n AlarmState.ALARM,\n ),\n AlarmRule.fromAlarm(\n new MonitorBurnRateForPeriod(scope, {\n ...sharedIndividualAlarmProps,\n alarmName: `ChildAlarmShortPeriod${alarmName}`,\n period: props.burnRateMonitoring.shortPeriod,\n }),\n AlarmState.ALARM,\n ),\n ),\n });\n this.addAlarmAction(new SnsAction(props.snsTopic));\n if (props.suppressorAlarm) {\n const cfnAlarm = this.node.defaultChild as CfnCompositeAlarm;\n cfnAlarm.actionsSuppressor = props.suppressorAlarm.alarmArn;\n cfnAlarm.actionsSuppressorWaitPeriod = 120;\n cfnAlarm.actionsSuppressorExtensionPeriod = props.burnRateMonitoring.shortPeriod.toSeconds();\n }\n }\n}\n"]}