Skip to content

Commit

Permalink
feat(cloudwatch): Additional Properties for Cloudwatch AlarmStatusWid…
Browse files Browse the repository at this point in the history
…get (#19387)

I've added the missing properties from the Alarm Status Widget

see: https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html#CloudWatch-Dashboard-Properties-Alarm-Widget-Object

fixes: #19386 

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
markussiebert authored Mar 24, 2022
1 parent 8f6e20e commit 3c9ea5f
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 10 deletions.
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,20 @@ dashboard.addWidgets(
);
```

An alarm status widget only showing firing alarms, sorted by state and timestamp:

```ts
declare const dashboard: cloudwatch.Dashboard;
declare const errorAlarm: cloudwatch.Alarm;

dashboard.addWidgets(new cloudwatch.AlarmStatusWidget({
title: "Errors",
alarms: [errorAlarm],
sortBy: cloudwatch.AlarmStatusWidgetSortBy.STATE_UPDATED_TIMESTAMP,
states: [cloudwatch.AlarmState.ALARM],
}));
```

### Query results widget

A `LogQueryWidget` shows the results of a query from Logs Insights:
Expand Down
47 changes: 47 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/lib/alarm-status-widget.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
import { IAlarm } from './alarm-base';
import { AlarmState } from './alarm-rule';
import { ConcreteWidget } from './widget';


/**
* The sort possibilities for AlarmStatusWidgets
*/
export enum AlarmStatusWidgetSortBy {

/**
* Choose DEFAULT to sort them in alphabetical order by alarm name.
*/
DEFAULT = 'default',

/**
* Choose STATE_UPDATED_TIMESTAMP to sort them first by alarm state, with alarms in ALARM state first,
* INSUFFICIENT_DATA alarms next, and OK alarms last.
* Within each group, the alarms are sorted by when they last changed state, with more recent state changes listed first.
*/
STATE_UPDATED_TIMESTAMP = 'stateUpdatedTimestamp',

/**
* Choose TIMESTAMP to sort them by the time when the alarms most recently changed state,
* no matter the current alarm state.
* The alarm that changed state most recently is listed first.
*/
TIMESTAMP = 'timestamp',
}

/**
* Properties for an Alarm Status Widget
*/
Expand All @@ -27,6 +54,24 @@ export interface AlarmStatusWidgetProps {
* @default 3
*/
readonly height?: number;

/**
* Specifies how to sort the alarms in the widget.
*
* @default - alphabetical order
*/
readonly sortBy?: AlarmStatusWidgetSortBy;

/**
* Use this field to filter the list of alarms displayed in the widget to only those alarms currently in the specified states.
* You can specify one or more alarm states in the value for this field.
* The alarm states that you can specify are ALARM, INSUFFICIENT_DATA, and OK.
*
* If you omit this field or specify an empty array, all the alarms specifed in alarms are displayed.
*
* @default - all the alarms specified in alarms are displayed.
*/
readonly states?: AlarmState[];
}

/**
Expand Down Expand Up @@ -56,6 +101,8 @@ export class AlarmStatusWidget extends ConcreteWidget {
properties: {
title: this.props.title ? this.props.title : 'Alarm Status',
alarms: this.props.alarms.map((alarm) => alarm.alarmArn),
states: this.props.states,
sortBy: this.props.sortBy,
},
},
];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Stack } from '@aws-cdk/core';
import { Metric, Alarm, AlarmStatusWidget } from '../lib';
import { Metric, Alarm, AlarmStatusWidget, AlarmStatusWidgetSortBy, AlarmState } from '../lib';
describe('Alarm Status Widget', () => {
test('alarm status widget', () => {
// GIVEN
Expand Down Expand Up @@ -28,7 +28,38 @@ describe('Alarm Status Widget', () => {
},
},
]);
});
test('alarm status widget custom props', () => {
// GIVEN
const stack = new Stack();
const metric = new Metric({ namespace: 'CDK', metricName: 'Test' });
const alarm = new Alarm(stack, 'Alarm', {
metric,
threshold: 1,
evaluationPeriods: 1,
});

// WHEN
const widget = new AlarmStatusWidget({
alarms: [alarm],
sortBy: AlarmStatusWidgetSortBy.STATE_UPDATED_TIMESTAMP,
states: [AlarmState.ALARM],
});

// THEN
expect(stack.resolve(widget.toJson())).toEqual([
{
type: 'alarm',
width: 6,
height: 3,
properties: {
title: 'Alarm Status',
alarms: [{ 'Fn::GetAtt': ['Alarm7103F465', 'Arn'] }],
sortBy: 'stateUpdatedTimestamp',
states: ['ALARM'],
},
},
]);

});
});
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@
"Arn"
]
},
"\"]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":6,\"x\":0,\"y\":8,\"properties\":{\"view\":\"timeSeries\",\"title\":\"More messages in queue with alarm annotation\",\"region\":\"",
"\"]},\"yAxis\":{}}},{\"type\":\"alarm\",\"width\":6,\"height\":3,\"x\":0,\"y\":8,\"properties\":{\"title\":\"Firing alarms\",\"alarms\":[\"",
{
"Fn::GetAtt": [
"Alarm7103F465",
"Arn"
]
},
"\"]}},{\"type\":\"metric\",\"width\":6,\"height\":6,\"x\":0,\"y\":11,\"properties\":{\"view\":\"timeSeries\",\"title\":\"More messages in queue with alarm annotation\",\"region\":\"",
{
"Ref": "AWS::Region"
},
Expand All @@ -56,7 +63,7 @@
"QueueName"
]
},
"\"]],\"annotations\":{\"horizontal\":[{\"label\":\"ApproximateNumberOfMessagesVisible >= 100 for 2 datapoints within 15 minutes\",\"value\":100,\"yAxis\":\"left\"}]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":14,\"properties\":{\"view\":\"singleValue\",\"title\":\"Current messages in queue\",\"region\":\"",
"\"]],\"annotations\":{\"horizontal\":[{\"label\":\"ApproximateNumberOfMessagesVisible >= 100 for 2 datapoints within 15 minutes\",\"value\":100,\"yAxis\":\"left\"}]},\"yAxis\":{}}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":17,\"properties\":{\"view\":\"singleValue\",\"title\":\"Current messages in queue\",\"region\":\"",
{
"Ref": "AWS::Region"
},
Expand All @@ -67,27 +74,27 @@
"QueueName"
]
},
"\"]]}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":17,\"properties\":{\"view\":\"table\",\"title\":\"Errors in my log group\",\"region\":\"",
"\"]]}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":20,\"properties\":{\"view\":\"table\",\"title\":\"Errors in my log group\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":23,\"properties\":{\"view\":\"bar\",\"title\":\"Errors in my log group - bar\",\"region\":\"",
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":26,\"properties\":{\"view\":\"bar\",\"title\":\"Errors in my log group - bar\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":29,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - line\",\"region\":\"",
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":32,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - line\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":false}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":35,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - stacked\",\"region\":\"",
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":false}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":38,\"properties\":{\"view\":\"timeSeries\",\"title\":\"Errors in my log group - stacked\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":true}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":41,\"properties\":{\"view\":\"pie\",\"title\":\"Errors in my log group - pie\",\"region\":\"",
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\",\"stacked\":true}},{\"type\":\"log\",\"width\":6,\"height\":6,\"x\":0,\"y\":44,\"properties\":{\"view\":\"pie\",\"title\":\"Errors in my log group - pie\",\"region\":\"",
{
"Ref": "AWS::Region"
},
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":47,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size\",\"region\":\"",
"\",\"query\":\"SOURCE 'my-log-group' | fields @message\\n | filter @message like /Error/\"}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":50,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size\",\"region\":\"",
{
"Ref": "AWS::Region"
},
Expand All @@ -98,7 +105,7 @@
"QueueName"
]
},
"\"]],\"singleValueFullPrecision\":false}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":50,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size with full precision\",\"region\":\"",
"\"]],\"singleValueFullPrecision\":false}},{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":53,\"properties\":{\"view\":\"singleValue\",\"title\":\"Sent message size with full precision\",\"region\":\"",
{
"Ref": "AWS::Region"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ dashboard.addWidgets(new cloudwatch.AlarmWidget({
title: 'Messages in queue',
alarm,
}));
dashboard.addWidgets(new cloudwatch.AlarmStatusWidget({
title: 'Firing alarms',
alarms: [alarm],
}));
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: 'More messages in queue with alarm annotation',
left: [numberOfMessagesVisibleMetric],
Expand Down

0 comments on commit 3c9ea5f

Please sign in to comment.