UNPKG

17.2 kBMarkdownView Raw
1# Amazon CloudWatch Construct Library
2<!--BEGIN STABILITY BANNER-->
3
4---
5
6![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)
7
8![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)
9
10---
11
12<!--END STABILITY BANNER-->
13
14## Metric objects
15
16Metric objects represent a metric that is emitted by AWS services or your own
17application, such as `CPUUsage`, `FailureCount` or `Bandwidth`.
18
19Metric objects can be constructed directly or are exposed by resources as
20attributes. Resources that expose metrics will have functions that look
21like `metricXxx()` which will return a Metric object, initialized with defaults
22that make sense.
23
24For example, `lambda.Function` objects have the `fn.metricErrors()` method, which
25represents the amount of errors reported by that Lambda function:
26
27```ts
28declare const fn: lambda.Function;
29
30const errors = fn.metricErrors();
31```
32
33`Metric` objects can be account and region aware. You can specify `account` and `region` as properties of the metric, or use the `metric.attachTo(Construct)` method. `metric.attachTo()` will automatically copy the `region` and `account` fields of the `Construct`, which can come from anywhere in the Construct tree.
34
35You can also instantiate `Metric` objects to reference any
36[published metric](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html)
37that's not exposed using a convenience method on the CDK construct.
38For example:
39
40```ts
41const hostedZone = new route53.HostedZone(this, 'MyHostedZone', { zoneName: "example.org" });
42const metric = new cloudwatch.Metric({
43 namespace: 'AWS/Route53',
44 metricName: 'DNSQueries',
45 dimensionsMap: {
46 HostedZoneId: hostedZone.hostedZoneId
47 }
48});
49```
50
51### Instantiating a new Metric object
52
53If you want to reference a metric that is not yet exposed by an existing construct,
54you can instantiate a `Metric` object to represent it. For example:
55
56```ts
57const metric = new cloudwatch.Metric({
58 namespace: 'MyNamespace',
59 metricName: 'MyMetric',
60 dimensionsMap: {
61 ProcessingStep: 'Download'
62 }
63});
64```
65
66### Metric Math
67
68Math expressions are supported by instantiating the `MathExpression` class.
69For example, a math expression that sums two other metrics looks like this:
70
71```ts
72declare const fn: lambda.Function;
73
74const allProblems = new cloudwatch.MathExpression({
75 expression: "errors + throttles",
76 usingMetrics: {
77 errors: fn.metricErrors(),
78 faults: fn.metricThrottles(),
79 }
80});
81```
82
83You can use `MathExpression` objects like any other metric, including using
84them in other math expressions:
85
86```ts
87declare const fn: lambda.Function;
88declare const allProblems: cloudwatch.MathExpression;
89
90const problemPercentage = new cloudwatch.MathExpression({
91 expression: "(problems / invocations) * 100",
92 usingMetrics: {
93 problems: allProblems,
94 invocations: fn.metricInvocations()
95 }
96});
97```
98
99### Search Expressions
100
101Math expressions also support search expressions. For example, the following
102search expression returns all CPUUtilization metrics that it finds, with the
103graph showing the Average statistic with an aggregation period of 5 minutes:
104
105```ts
106const cpuUtilization = new cloudwatch.MathExpression({
107 expression: "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)",
108
109 // Specifying '' as the label suppresses the default behavior
110 // of using the expression as metric label. This is especially appropriate
111 // when using expressions that return multiple time series (like SEARCH()
112 // or METRICS()), to show the labels of the retrieved metrics only.
113 label: '',
114});
115```
116
117Cross-account and cross-region search expressions are also supported. Use
118the `searchAccount` and `searchRegion` properties to specify the account
119and/or region to evaluate the search expression against.
120
121### Aggregation
122
123To graph or alarm on metrics you must aggregate them first, using a function
124like `Average` or a percentile function like `P99`. By default, most Metric objects
125returned by CDK libraries will be configured as `Average` over `300 seconds` (5 minutes).
126The exception is if the metric represents a count of discrete events, such as
127failures. In that case, the Metric object will be configured as `Sum` over `300
128seconds`, i.e. it represents the number of times that event occurred over the
129time period.
130
131If you want to change the default aggregation of the Metric object (for example,
132the function or the period), you can do so by passing additional parameters
133to the metric function call:
134
135```ts
136declare const fn: lambda.Function;
137
138const minuteErrorRate = fn.metricErrors({
139 statistic: 'avg',
140 period: Duration.minutes(1),
141 label: 'Lambda failure rate'
142});
143```
144
145This function also allows changing the metric label or color (which will be
146useful when embedding them in graphs, see below).
147
148> Rates versus Sums
149>
150> The reason for using `Sum` to count discrete events is that *some* events are
151> emitted as either `0` or `1` (for example `Errors` for a Lambda) and some are
152> only emitted as `1` (for example `NumberOfMessagesPublished` for an SNS
153> topic).
154>
155> In case `0`-metrics are emitted, it makes sense to take the `Average` of this
156> metric: the result will be the fraction of errors over all executions.
157>
158> If `0`-metrics are not emitted, the `Average` will always be equal to `1`,
159> and not be very useful.
160>
161> In order to simplify the mental model of `Metric` objects, we default to
162> aggregating using `Sum`, which will be the same for both metrics types. If you
163> happen to know the Metric you want to alarm on makes sense as a rate
164> (`Average`) you can always choose to change the statistic.
165
166### Labels
167
168Metric labels are displayed in the legend of graphs that include the metrics.
169
170You can use [dynamic labels](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/graph-dynamic-labels.html)
171to show summary information about the displayed time series
172in the legend. For example, if you use:
173
174```ts
175declare const fn: lambda.Function;
176
177const minuteErrorRate = fn.metricErrors({
178 statistic: 'sum',
179 period: Duration.hours(1),
180
181 // Show the maximum hourly error count in the legend
182 label: '[max: ${MAX}] Lambda failure rate',
183});
184```
185
186As the metric label, the maximum value in the visible range will
187be shown next to the time series name in the graph's legend.
188
189If the metric is a math expression producing more than one time series, the
190maximum will be individually calculated and shown for each time series produce
191by the math expression.
192
193## Alarms
194
195Alarms can be created on metrics in one of two ways. Either create an `Alarm`
196object, passing the `Metric` object to set the alarm on:
197
198```ts
199declare const fn: lambda.Function;
200
201new cloudwatch.Alarm(this, 'Alarm', {
202 metric: fn.metricErrors(),
203 threshold: 100,
204 evaluationPeriods: 2,
205});
206```
207
208Alternatively, you can call `metric.createAlarm()`:
209
210```ts
211declare const fn: lambda.Function;
212
213fn.metricErrors().createAlarm(this, 'Alarm', {
214 threshold: 100,
215 evaluationPeriods: 2,
216});
217```
218
219The most important properties to set while creating an Alarms are:
220
221- `threshold`: the value to compare the metric against.
222- `comparisonOperator`: the comparison operation to use, defaults to `metric >= threshold`.
223- `evaluationPeriods`: how many consecutive periods the metric has to be
224 breaching the the threshold for the alarm to trigger.
225
226To create a cross-account alarm, make sure you have enabled [cross-account functionality](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Cross-Account-Cross-Region.html) in CloudWatch. Then, set the `account` property in the `Metric` object either manually or via the `metric.attachTo()` method.
227
228### Alarm Actions
229
230To add actions to an alarm, use the integration classes from the
231`@aws-cdk/aws-cloudwatch-actions` package. For example, to post a message to
232an SNS topic when an alarm breaches, do the following:
233
234```ts
235import * as cw_actions from '@aws-cdk/aws-cloudwatch-actions';
236declare const alarm: cloudwatch.Alarm;
237
238const topic = new sns.Topic(this, 'Topic');
239alarm.addAlarmAction(new cw_actions.SnsAction(topic));
240```
241
242#### Notification formats
243
244Alarms can be created in one of two "formats":
245
246- With "top-level parameters" (these are the classic style of CloudWatch Alarms).
247- With a list of metrics specifications (these are the modern style of CloudWatch Alarms).
248
249For backwards compatibility, CDK will try to create classic, top-level CloudWatch alarms
250as much as possible, unless you are using features that cannot be expressed in that format.
251Features that require the new-style alarm format are:
252
253- Metric math
254- Cross-account metrics
255- Labels
256
257The difference between these two does not impact the functionality of the alarm
258in any way, *except* that the format of the notifications the Alarm generates is
259different between them. This affects both the notifications sent out over SNS,
260as well as the EventBridge events generated by this Alarm. If you are writing
261code to consume these notifications, be sure to handle both formats.
262
263### Composite Alarms
264
265[Composite Alarms](https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-cloudwatch-now-allows-you-to-combine-multiple-alarms/)
266can be created from existing Alarm resources.
267
268```ts
269declare const alarm1: cloudwatch.Alarm;
270declare const alarm2: cloudwatch.Alarm;
271declare const alarm3: cloudwatch.Alarm;
272declare const alarm4: cloudwatch.Alarm;
273
274const alarmRule = cloudwatch.AlarmRule.anyOf(
275 cloudwatch.AlarmRule.allOf(
276 cloudwatch.AlarmRule.anyOf(
277 alarm1,
278 cloudwatch.AlarmRule.fromAlarm(alarm2, cloudwatch.AlarmState.OK),
279 alarm3,
280 ),
281 cloudwatch.AlarmRule.not(cloudwatch.AlarmRule.fromAlarm(alarm4, cloudwatch.AlarmState.INSUFFICIENT_DATA)),
282 ),
283 cloudwatch.AlarmRule.fromBoolean(false),
284);
285
286new cloudwatch.CompositeAlarm(this, 'MyAwesomeCompositeAlarm', {
287 alarmRule,
288});
289```
290
291### A note on units
292
293In CloudWatch, Metrics datums are emitted with units, such as `seconds` or
294`bytes`. When `Metric` objects are given a `unit` attribute, it will be used to
295*filter* the stream of metric datums for datums emitted using the same `unit`
296attribute.
297
298In particular, the `unit` field is *not* used to rescale datums or alarm threshold
299values (for example, it cannot be used to specify an alarm threshold in
300*Megabytes* if the metric stream is being emitted as *bytes*).
301
302You almost certainly don't want to specify the `unit` property when creating
303`Metric` objects (which will retrieve all datums regardless of their unit),
304unless you have very specific requirements. Note that in any case, CloudWatch
305only supports filtering by `unit` for Alarms, not in Dashboard graphs.
306
307Please see the following GitHub issue for a discussion on real unit
308calculations in CDK: https://github.com/aws/aws-cdk/issues/5595
309
310## Dashboards
311
312Dashboards are set of Widgets stored server-side which can be accessed quickly
313from the AWS console. Available widgets are graphs of a metric over time, the
314current value of a metric, or a static piece of Markdown which explains what the
315graphs mean.
316
317The following widgets are available:
318
319- `GraphWidget` -- shows any number of metrics on both the left and right
320 vertical axes.
321- `AlarmWidget` -- shows the graph and alarm line for a single alarm.
322- `SingleValueWidget` -- shows the current value of a set of metrics.
323- `TextWidget` -- shows some static Markdown.
324- `AlarmStatusWidget` -- shows the status of your alarms in a grid view.
325
326### Graph widget
327
328A graph widget can display any number of metrics on either the `left` or
329`right` vertical axis:
330
331```ts
332declare const dashboard: cloudwatch.Dashboard;
333declare const executionCountMetric: cloudwatch.Metric;
334declare const errorCountMetric: cloudwatch.Metric;
335
336dashboard.addWidgets(new cloudwatch.GraphWidget({
337 title: "Executions vs error rate",
338
339 left: [executionCountMetric],
340
341 right: [errorCountMetric.with({
342 statistic: "average",
343 label: "Error rate",
344 color: cloudwatch.Color.GREEN,
345 })]
346}));
347```
348
349Using the methods `addLeftMetric()` and `addRightMetric()` you can add metrics to a graph widget later on.
350
351Graph widgets can also display annotations attached to the left or the right y-axis.
352
353```ts
354declare const dashboard: cloudwatch.Dashboard;
355
356dashboard.addWidgets(new cloudwatch.GraphWidget({
357 // ...
358
359 leftAnnotations: [
360 { value: 1800, label: Duration.minutes(30).toHumanString(), color: cloudwatch.Color.RED, },
361 { value: 3600, label: '1 hour', color: '#2ca02c', }
362 ],
363}));
364```
365
366The graph legend can be adjusted from the default position at bottom of the widget.
367
368```ts
369declare const dashboard: cloudwatch.Dashboard;
370
371dashboard.addWidgets(new cloudwatch.GraphWidget({
372 // ...
373
374 legendPosition: cloudwatch.LegendPosition.RIGHT,
375}));
376```
377
378The graph can publish live data within the last minute that has not been fully aggregated.
379
380```ts
381declare const dashboard: cloudwatch.Dashboard;
382
383dashboard.addWidgets(new cloudwatch.GraphWidget({
384 // ...
385
386 liveData: true,
387}));
388```
389
390The graph view can be changed from default 'timeSeries' to 'bar' or 'pie'.
391
392```ts
393declare const dashboard: cloudwatch.Dashboard;
394
395dashboard.addWidgets(new cloudwatch.GraphWidget({
396 // ...
397
398 view: cloudwatch.GraphWidgetView.BAR,
399}));
400```
401
402### Alarm widget
403
404An alarm widget shows the graph and the alarm line of a single alarm:
405
406```ts
407declare const dashboard: cloudwatch.Dashboard;
408declare const errorAlarm: cloudwatch.Alarm;
409
410dashboard.addWidgets(new cloudwatch.AlarmWidget({
411 title: "Errors",
412 alarm: errorAlarm,
413}));
414```
415
416### Single value widget
417
418A single-value widget shows the latest value of a set of metrics (as opposed
419to a graph of the value over time):
420
421```ts
422declare const dashboard: cloudwatch.Dashboard;
423declare const visitorCount: cloudwatch.Metric;
424declare const purchaseCount: cloudwatch.Metric;
425
426dashboard.addWidgets(new cloudwatch.SingleValueWidget({
427 metrics: [visitorCount, purchaseCount],
428}));
429```
430
431Show as many digits as can fit, before rounding.
432
433```ts
434declare const dashboard: cloudwatch.Dashboard;
435
436dashboard.addWidgets(new cloudwatch.SingleValueWidget({
437 metrics: [ /* ... */ ],
438
439 fullPrecision: true,
440}));
441```
442
443### Text widget
444
445A text widget shows an arbitrary piece of MarkDown. Use this to add explanations
446to your dashboard:
447
448```ts
449declare const dashboard: cloudwatch.Dashboard;
450
451dashboard.addWidgets(new cloudwatch.TextWidget({
452 markdown: '# Key Performance Indicators'
453}));
454```
455
456### Alarm Status widget
457
458An alarm status widget displays instantly the status of any type of alarms and gives the
459ability to aggregate one or more alarms together in a small surface.
460
461```ts
462declare const dashboard: cloudwatch.Dashboard;
463declare const errorAlarm: cloudwatch.Alarm;
464
465dashboard.addWidgets(
466 new cloudwatch.AlarmStatusWidget({
467 alarms: [errorAlarm],
468 })
469);
470```
471
472An alarm status widget only showing firing alarms, sorted by state and timestamp:
473
474```ts
475declare const dashboard: cloudwatch.Dashboard;
476declare const errorAlarm: cloudwatch.Alarm;
477
478dashboard.addWidgets(new cloudwatch.AlarmStatusWidget({
479 title: "Errors",
480 alarms: [errorAlarm],
481 sortBy: cloudwatch.AlarmStatusWidgetSortBy.STATE_UPDATED_TIMESTAMP,
482 states: [cloudwatch.AlarmState.ALARM],
483}));
484```
485
486### Query results widget
487
488A `LogQueryWidget` shows the results of a query from Logs Insights:
489
490```ts
491declare const dashboard: cloudwatch.Dashboard;
492
493dashboard.addWidgets(new cloudwatch.LogQueryWidget({
494 logGroupNames: ['my-log-group'],
495 view: cloudwatch.LogQueryVisualizationType.TABLE,
496 // The lines will be automatically combined using '\n|'.
497 queryLines: [
498 'fields @message',
499 'filter @message like /Error/',
500 ]
501}));
502```
503
504### Custom widget
505
506A `CustomWidget` shows the result of an AWS Lambda function:
507
508```ts
509declare const dashboard: cloudwatch.Dashboard;
510
511// Import or create a lambda function
512const fn = lambda.Function.fromFunctionArn(
513 dashboard,
514 'Function',
515 'arn:aws:lambda:us-east-1:123456789012:function:MyFn',
516);
517
518dashboard.addWidgets(new cloudwatch.CustomWidget({
519 functionArn: fn.functionArn,
520 title: 'My lambda baked widget',
521}));
522```
523
524You can learn more about custom widgets in the [Amazon Cloudwatch User Guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/add_custom_widget_dashboard.html).
525
526### Dashboard Layout
527
528The widgets on a dashboard are visually laid out in a grid that is 24 columns
529wide. Normally you specify X and Y coordinates for the widgets on a Dashboard,
530but because this is inconvenient to do manually, the library contains a simple
531layout system to help you lay out your dashboards the way you want them to.
532
533Widgets have a `width` and `height` property, and they will be automatically
534laid out either horizontally or vertically stacked to fill out the available
535space.
536
537Widgets are added to a Dashboard by calling `add(widget1, widget2, ...)`.
538Widgets given in the same call will be laid out horizontally. Widgets given
539in different calls will be laid out vertically. To make more complex layouts,
540you can use the following widgets to pack widgets together in different ways:
541
542- `Column`: stack two or more widgets vertically.
543- `Row`: lay out two or more widgets horizontally.
544- `Spacer`: take up empty space