forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdashboard.ts
225 lines (196 loc) · 6.7 KB
/
dashboard.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import { Construct } from 'constructs';
import { CfnDashboard } from './cloudwatch.generated';
import { Column, Row } from './layout';
import { IVariable } from './variable';
import { IWidget } from './widget';
import { Lazy, Resource, Stack, Token, Annotations, Duration } from '../../core';
/**
* Specify the period for graphs when the CloudWatch dashboard loads
*/
export enum PeriodOverride {
/**
* Period of all graphs on the dashboard automatically adapt to the time range of the dashboard.
*/
AUTO = 'auto',
/**
* Period set for each graph will be used
*/
INHERIT = 'inherit',
}
/**
* Properties for defining a CloudWatch Dashboard
*/
export interface DashboardProps {
/**
* Name of the dashboard.
*
* If set, must only contain alphanumerics, dash (-) and underscore (_)
*
* @default - automatically generated name
*/
readonly dashboardName?: string;
/**
* Interval duration for metrics.
* You can specify defaultInterval with the relative time(eg. cdk.Duration.days(7)).
*
* Both properties `defaultInterval` and `start` cannot be set at once.
*
* @default When the dashboard loads, the defaultInterval time will be the default time range.
*/
readonly defaultInterval?: Duration
/**
* The start of the time range to use for each widget on the dashboard.
* You can specify start without specifying end to specify a relative time range that ends with the current time.
* In this case, the value of start must begin with -P, and you can use M, H, D, W and M as abbreviations for
* minutes, hours, days, weeks and months. For example, -PT8H shows the last 8 hours and -P3M shows the last three months.
* You can also use start along with an end field, to specify an absolute time range.
* When specifying an absolute time range, use the ISO 8601 format. For example, 2018-12-17T06:00:00.000Z.
*
* Both properties `defaultInterval` and `start` cannot be set at once.
*
* @default When the dashboard loads, the start time will be the default time range.
*/
readonly start?: string;
/**
* The end of the time range to use for each widget on the dashboard when the dashboard loads.
* If you specify a value for end, you must also specify a value for start.
* Specify an absolute time in the ISO 8601 format. For example, 2018-12-17T06:00:00.000Z.
*
* @default When the dashboard loads, the end date will be the current time.
*/
readonly end?: string;
/**
* Use this field to specify the period for the graphs when the dashboard loads.
* Specifying `Auto` causes the period of all graphs on the dashboard to automatically adapt to the time range of the dashboard.
* Specifying `Inherit` ensures that the period set for each graph is always obeyed.
*
* @default Auto
*/
readonly periodOverride?: PeriodOverride;
/**
* Initial set of widgets on the dashboard
*
* One array represents a row of widgets.
*
* @default - No widgets
*/
readonly widgets?: IWidget[][]
/**
* A list of dashboard variables
*
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_dashboard_variables.html#cloudwatch_dashboard_variables_types
*
* @default - No variables
*/
readonly variables?: IVariable[];
}
/**
* A CloudWatch dashboard
*/
export class Dashboard extends Resource {
/**
* The name of this dashboard
*
* @attribute
*/
public readonly dashboardName: string;
/**
* ARN of this dashboard
*
* @attribute
*/
public readonly dashboardArn: string;
private readonly rows: IWidget[] = [];
private readonly variables: IVariable[] = [];
constructor(scope: Construct, id: string, props: DashboardProps = {}) {
super(scope, id, {
physicalName: props.dashboardName,
});
{
const { dashboardName } = props;
if (dashboardName && !Token.isUnresolved(dashboardName) && !dashboardName.match(/^[\w-]+$/)) {
throw new Error([
`The value ${dashboardName} for field dashboardName contains invalid characters.`,
'It can only contain alphanumerics, dash (-) and underscore (_).',
].join(' '));
}
}
if (props.start !== undefined && props.defaultInterval !== undefined) {
throw ('both properties defaultInterval and start cannot be set at once');
}
const dashboard = new CfnDashboard(this, 'Resource', {
dashboardName: this.physicalName,
dashboardBody: Lazy.string({
produce: () => {
const column = new Column(...this.rows);
column.position(0, 0);
return Stack.of(this).toJsonString({
start: props.defaultInterval !== undefined ? `-${props.defaultInterval?.toIsoString()}` : props.start,
end: props.defaultInterval !== undefined ? undefined : props.end,
periodOverride: props.periodOverride,
widgets: column.toJson(),
variables: this.variables.length > 0 ? this.variables.map(variable => variable.toJson()) : undefined,
});
},
}),
});
this.dashboardName = this.getResourceNameAttribute(dashboard.ref);
(props.widgets || []).forEach(row => {
this.addWidgets(...row);
});
(props.variables || []).forEach(variable => this.addVariable(variable));
this.dashboardArn = Stack.of(this).formatArn({
service: 'cloudwatch',
resource: 'dashboard',
region: '',
resourceName: this.physicalName,
});
}
/**
* Add a widget to the dashboard.
*
* Widgets given in multiple calls to add() will be laid out stacked on
* top of each other.
*
* Multiple widgets added in the same call to add() will be laid out next
* to each other.
*/
public addWidgets(...widgets: IWidget[]) {
if (widgets.length === 0) {
return;
}
const warnings = allWidgetsDeep(widgets).reduce((prev, curr) => {
return {
...prev,
...curr.warningsV2,
};
}, {} as { [id: string]: string });
for (const [id, message] of Object.entries(warnings ?? {})) {
Annotations.of(this).addWarningV2(id, message);
}
const w = widgets.length > 1 ? new Row(...widgets) : widgets[0];
this.rows.push(w);
}
/**
* Add a variable to the dashboard.
*
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_dashboard_variables.html
*/
public addVariable(variable: IVariable) {
this.variables.push(variable);
}
}
function allWidgetsDeep(ws: IWidget[]) {
const ret = new Array<IWidget>();
ws.forEach(recurse);
return ret;
function recurse(w: IWidget) {
ret.push(w);
if (hasSubWidgets(w)) {
w.widgets.forEach(recurse);
}
}
}
function hasSubWidgets(w: IWidget): w is IWidget & { widgets: IWidget[] } {
return 'widgets' in w;
}