UNPKG

14.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.dispatchMetric = exports.metricPeriod = exports.metricKey = void 0;
4const core_1 = require("@aws-cdk/core");
5const METRICKEY_SYMBOL = Symbol('@aws-cdk/aws-cloudwatch.MetricKey');
6/**
7 * Return a unique string representation for this metric.
8 *
9 * Can be used to determine as a hash key to determine if 2 Metric objects
10 * represent the same metric. Excludes rendering properties.
11 */
12function metricKey(metric) {
13 // Cache on the object itself. This is safe because Metric objects are immutable.
14 if (metric.hasOwnProperty(METRICKEY_SYMBOL)) {
15 return metric[METRICKEY_SYMBOL];
16 }
17 const parts = new Array();
18 const conf = metric.toMetricConfig();
19 if (conf.mathExpression) {
20 parts.push(conf.mathExpression.expression);
21 for (const id of Object.keys(conf.mathExpression.usingMetrics).sort()) {
22 parts.push(id);
23 parts.push(metricKey(conf.mathExpression.usingMetrics[id]));
24 }
25 if (conf.mathExpression.searchRegion) {
26 parts.push(conf.mathExpression.searchRegion);
27 }
28 if (conf.mathExpression.searchAccount) {
29 parts.push(conf.mathExpression.searchAccount);
30 }
31 }
32 if (conf.metricStat) {
33 parts.push(conf.metricStat.namespace);
34 parts.push(conf.metricStat.metricName);
35 for (const dim of conf.metricStat.dimensions || []) {
36 parts.push(dim.name);
37 parts.push(dim.value);
38 }
39 if (conf.metricStat.statistic) {
40 parts.push(conf.metricStat.statistic);
41 }
42 if (conf.metricStat.period) {
43 parts.push(`${conf.metricStat.period.toSeconds()}`);
44 }
45 if (conf.metricStat.region) {
46 parts.push(conf.metricStat.region);
47 }
48 if (conf.metricStat.account) {
49 parts.push(conf.metricStat.account);
50 }
51 }
52 const ret = parts.join('|');
53 Object.defineProperty(metric, METRICKEY_SYMBOL, { value: ret });
54 return ret;
55}
56exports.metricKey = metricKey;
57/**
58 * Return the period of a metric
59 *
60 * For a stat metric, return the immediate period.
61 *
62 * For an expression metric, all metrics used in it have been made to have the
63 * same period, so we return the period of the first inner metric.
64 */
65function metricPeriod(metric) {
66 return dispatchMetric(metric, {
67 withStat(stat) {
68 return stat.period;
69 },
70 withExpression() {
71 return metric.period || core_1.Duration.minutes(5);
72 },
73 });
74}
75exports.metricPeriod = metricPeriod;
76/**
77 * Given a metric object, inspect it and call the correct function for the type of output
78 *
79 * In addition to the metric object itself, takes a callback object with two
80 * methods, to be invoked for the particular type of metric.
81 *
82 * If the metric represent a metric query (nominally generated through an
83 * instantiation of `Metric` but can be generated by any class that implements
84 * `IMetric`) a particular field in its `toMetricConfig()` output will be set
85 * (to wit, `metricStat`) and the `withStat()` callback will be called with
86 * that object.
87 *
88 * If the metric represents an expression (usually by instantiating `MathExpression`
89 * but users can implement `IMetric` arbitrarily) the `mathExpression` field
90 * will be set in the object returned from `toMetricConfig` and the callback
91 * called `withExpression` will be applied to that object.
92 *
93 * Will return the values returned by the callbacks.
94 *
95 * To be used as such:
96 *
97 * ```ts
98 * const ret = dispatchMetric(someMetric, {
99 * withStat(stat) {
100 * // do something with stat
101 * return 1;
102 * },
103 * withExpression(expr) {
104 * // do something with expr
105 * return 2;
106 * },
107 * });
108 * ```
109 *
110 * This function encapsulates some type analysis that would otherwise have to be
111 * repeated in all places where code needs to make a distinction on the type
112 * of metric object that is being passed.
113 */
114// eslint-disable-next-line max-len
115function dispatchMetric(metric, fns) {
116 const conf = metric.toMetricConfig();
117 if (conf.metricStat && conf.mathExpression) {
118 throw new Error('Metric object must not produce both \'metricStat\' and \'mathExpression\'');
119 }
120 else if (conf.metricStat) {
121 return fns.withStat(conf.metricStat, conf);
122 }
123 else if (conf.mathExpression) {
124 return fns.withExpression(conf.mathExpression, conf);
125 }
126 else {
127 throw new Error('Metric object must have either \'metricStat\' or \'mathExpression\'');
128 }
129}
130exports.dispatchMetric = dispatchMetric;
131//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljLXV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJtZXRyaWMtdXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx3Q0FBeUM7QUFJekMsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsbUNBQW1DLENBQUMsQ0FBQztBQUVyRTs7Ozs7R0FLRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxNQUFlO0lBQ3ZDLGlGQUFpRjtJQUNqRixJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtRQUMzQyxPQUFRLE1BQWMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0tBQzFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLEVBQVUsQ0FBQztJQUVsQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDckMsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFO1FBQ3ZCLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMzQyxLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUNyRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2YsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQzdEO1FBQ0QsSUFBSSxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksRUFBRTtZQUNwQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLENBQUM7U0FDOUM7UUFDRCxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsYUFBYSxFQUFFO1lBQ3JDLEtBQUssQ0FBQyxJQUFJLENBQUMs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ImltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBNYXRoRXhwcmVzc2lvbiB9IGZyb20gJy4uL21ldHJpYyc7XG5pbXBvcnQgeyBJTWV0cmljLCBNZXRyaWNDb25maWcsIE1ldHJpY0V4cHJlc3Npb25Db25maWcsIE1ldHJpY1N0YXRDb25maWcgfSBmcm9tICcuLi9tZXRyaWMtdHlwZXMnO1xuXG5jb25zdCBNRVRSSUNLRVlfU1lNQk9MID0gU3ltYm9sKCdAYXdzLWNkay9hd3MtY2xvdWR3YXRjaC5NZXRyaWNLZXknKTtcblxuLyoqXG4gKiBSZXR1cm4gYSB1bmlxdWUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGZvciB0aGlzIG1ldHJpYy5cbiAqXG4gKiBDYW4gYmUgdXNlZCB0byBkZXRlcm1pbmUgYXMgYSBoYXNoIGtleSB0byBkZXRlcm1pbmUgaWYgMiBNZXRyaWMgb2JqZWN0c1xuICogcmVwcmVzZW50IHRoZSBzYW1lIG1ldHJpYy4gRXhjbHVkZXMgcmVuZGVyaW5nIHByb3BlcnRpZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXRyaWNLZXkobWV0cmljOiBJTWV0cmljKTogc3RyaW5nIHtcbiAgLy8gQ2FjaGUgb24gdGhlIG9iamVjdCBpdHNlbGYuIFRoaXMgaXMgc2FmZSBiZWNhdXNlIE1ldHJpYyBvYmplY3RzIGFyZSBpbW11dGFibGUuXG4gIGlmIChtZXRyaWMuaGFzT3duUHJvcGVydHkoTUVUUklDS0VZX1NZTUJPTCkpIHtcbiAgICByZXR1cm4gKG1ldHJpYyBhcyBhbnkpW01FVFJJQ0tFWV9TWU1CT0xdO1xuICB9XG5cbiAgY29uc3QgcGFydHMgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuXG4gIGNvbnN0IGNvbmYgPSBtZXRyaWMudG9NZXRyaWNDb25maWcoKTtcbiAgaWYgKGNvbmYubWF0aEV4cHJlc3Npb24pIHtcbiAgICBwYXJ0cy5wdXNoKGNvbmYubWF0aEV4cHJlc3Npb24uZXhwcmVzc2lvbik7XG4gICAgZm9yIChjb25zdCBpZCBvZiBPYmplY3Qua2V5cyhjb25mLm1hdGhFeHByZXNzaW9uLnVzaW5nTWV0cmljcykuc29ydCgpKSB7XG4gICAgICBwYXJ0cy5wdXNoKGlkKTtcbiAgICAgIHBhcnRzLnB1c2gobWV0cmljS2V5KGNvbmYubWF0aEV4cHJlc3Npb24udXNpbmdNZXRyaWNzW2lkXSkpO1xuICAgIH1cbiAgICBpZiAoY29uZi5tYXRoRXhwcmVzc2lvbi5zZWFyY2hSZWdpb24pIHtcbiAgICAgIHBhcnRzLnB1c2goY29uZi5tYXRoRXhwcmVzc2lvbi5zZWFyY2hSZWdpb24pO1xuICAgIH1cbiAgICBpZiAoY29uZi5tYXRoRXhwcmVzc2lvbi5zZWFyY2hBY2NvdW50KSB7XG4gICAgICBwYXJ0cy5wdXNoKGNvbmYubWF0aEV4cHJlc3Npb24uc2VhcmNoQWNjb3VudCk7XG4gICAgfVxuICB9XG4gIGlmIChjb25mLm1ldHJpY1N0YXQpIHtcbiAgICBwYXJ0cy5wdXNoKGNvbmYubWV0cmljU3RhdC5uYW1lc3BhY2UpO1xuICAgIHBhcnRzLnB1c2goY29uZi5tZXRyaWNTdGF0Lm1ldHJpY05hbWUpO1xuICAgIGZvciAoY29uc3QgZGltIG9mIGNvbmYubWV0cmljU3RhdC5kaW1lbnNpb25zIHx8IFtdKSB7XG4gICAgICBwYXJ0cy5wdXNoKGRpbS5uYW1lKTtcbiAgICAgIHBhcnRzLnB1c2goZGltLnZhbHVlKTtcbiAgICB9XG4gICAgaWYgKGNvbmYubWV0cmljU3RhdC5zdGF0aXN0aWMpIHtcbiAgICAgIHBhcnRzLnB1c2goY29uZi5tZXRyaWNTdGF0LnN0YXRpc3RpYyk7XG4gICAgfVxuICAgIGlmIChjb25mLm1ldHJpY1N0YXQucGVyaW9kKSB7XG4gICAgICBwYXJ0cy5wdXNoKGAke2NvbmYubWV0cmljU3RhdC5wZXJpb2QudG9TZWNvbmRzKCl9YCk7XG4gICAgfVxuICAgIGlmIChjb25mLm1ldHJpY1N0YXQucmVnaW9uKSB7XG4gICAgICBwYXJ0cy5wdXNoKGNvbmYubWV0cmljU3RhdC5yZWdpb24pO1xuICAgIH1cbiAgICBpZiAoY29uZi5tZXRyaWNTdGF0LmFjY291bnQpIHtcbiAgICAgIHBhcnRzLnB1c2goY29uZi5tZXRyaWNTdGF0LmFjY291bnQpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJldCA9IHBhcnRzLmpvaW4oJ3wnKTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG1ldHJpYywgTUVUUklDS0VZX1NZTUJPTCwgeyB2YWx1ZTogcmV0IH0pO1xuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIFJldHVybiB0aGUgcGVyaW9kIG9mIGEgbWV0cmljXG4gKlxuICogRm9yIGEgc3RhdCBtZXRyaWMsIHJldHVybiB0aGUgaW1tZWRpYXRlIHBlcmlvZC5cbiAqXG4gKiBGb3IgYW4gZXhwcmVzc2lvbiBtZXRyaWMsIGFsbCBtZXRyaWNzIHVzZWQgaW4gaXQgaGF2ZSBiZWVuIG1hZGUgdG8gaGF2ZSB0aGVcbiAqIHNhbWUgcGVyaW9kLCBzbyB3ZSByZXR1cm4gdGhlIHBlcmlvZCBvZiB0aGUgZmlyc3QgaW5uZXIgbWV0cmljLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWV0cmljUGVyaW9kKG1ldHJpYzogSU1ldHJpYyk6IER1cmF0aW9uIHtcbiAgcmV0dXJuIGRpc3BhdGNoTWV0cmljKG1ldHJpYywge1xuICAgIHdpdGhTdGF0KHN0YXQpIHtcbiAgICAgIHJldHVybiBzdGF0LnBlcmlvZDtcbiAgICB9LFxuICAgIHdpdGhFeHByZXNzaW9uKCkge1xuICAgICAgcmV0dXJuIChtZXRyaWMgYXMgTWF0aEV4cHJlc3Npb24pLnBlcmlvZCB8fCBEdXJhdGlvbi5taW51dGVzKDUpO1xuICAgIH0sXG4gIH0pO1xufVxuXG4vKipcbiAqIEdpdmVuIGEgbWV0cmljIG9iamVjdCwgaW5zcGVjdCBpdCBhbmQgY2FsbCB0aGUgY29ycmVjdCBmdW5jdGlvbiBmb3IgdGhlIHR5cGUgb2Ygb3V0cHV0XG4gKlxuICogSW4gYWRkaXRpb24gdG8gdGhlIG1ldHJpYyBvYmplY3QgaXRzZWxmLCB0YWtlcyBhIGNhbGxiYWNrIG9iamVjdCB3aXRoIHR3b1xuICogbWV0aG9kcywgdG8gYmUgaW52b2tlZCBmb3IgdGhlIHBhcnRpY3VsYXIgdHlwZSBvZiBtZXRyaWMuXG4gKlxuICogSWYgdGhlIG1ldHJpYyByZXByZXNlbnQgYSBtZXRyaWMgcXVlcnkgKG5vbWluYWxseSBnZW5lcmF0ZWQgdGhyb3VnaCBhblxuICogaW5zdGFudGlhdGlvbiBvZiBgTWV0cmljYCBidXQgY2FuIGJlIGdlbmVyYXRlZCBieSBhbnkgY2xhc3MgdGhhdCBpbXBsZW1lbnRzXG4gKiBgSU1ldHJpY2ApIGEgcGFydGljdWxhciBmaWVsZCBpbiBpdHMgYHRvTWV0cmljQ29uZmlnKClgIG91dHB1dCB3aWxsIGJlIHNldFxuICogKHRvIHdpdCwgYG1ldHJpY1N0YXRgKSBhbmQgdGhlIGB3aXRoU3RhdCgpYCBjYWxsYmFjayB3aWxsIGJlIGNhbGxlZCB3aXRoXG4gKiB0aGF0IG9iamVjdC5cbiAqXG4gKiBJZiB0aGUgbWV0cmljIHJlcHJlc2VudHMgYW4gZXhwcmVzc2lvbiAodXN1YWxseSBieSBpbnN0YW50aWF0aW5nIGBNYXRoRXhwcmVzc2lvbmBcbiAqIGJ1dCB1c2VycyBjYW4gaW1wbGVtZW50IGBJTWV0cmljYCBhcmJpdHJhcmlseSkgdGhlIGBtYXRoRXhwcmVzc2lvbmAgZmllbGRcbiAqIHdpbGwgYmUgc2V0IGluIHRoZSBvYmplY3QgcmV0dXJuZWQgZnJvbSBgdG9NZXRyaWNDb25maWdgIGFuZCB0aGUgY2FsbGJhY2tcbiAqIGNhbGxlZCBgd2l0aEV4cHJlc3Npb25gIHdpbGwgYmUgYXBwbGllZCB0byB0aGF0IG9iamVjdC5cbiAqXG4gKiBXaWxsIHJldHVybiB0aGUgdmFsdWVzIHJldHVybmVkIGJ5IHRoZSBjYWxsYmFja3MuXG4gKlxuICogVG8gYmUgdXNlZCBhcyBzdWNoOlxuICpcbiAqIGBgYHRzXG4gKiBjb25zdCByZXQgPSBkaXNwYXRjaE1ldHJpYyhzb21lTWV0cmljLCB7XG4gKiAgIHdpdGhTdGF0KHN0YXQpIHtcbiAqICAgICAvLyBkbyBzb21ldGhpbmcgd2l0aCBzdGF0XG4gKiAgICAgcmV0dXJuIDE7XG4gKiAgIH0sXG4gKiAgIHdpdGhFeHByZXNzaW9uKGV4cHIpIHtcbiAqICAgICAvLyBkbyBzb21ldGhpbmcgd2l0aCBleHByXG4gKiAgICAgcmV0dXJuIDI7XG4gKiAgIH0sXG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFRoaXMgZnVuY3Rpb24gZW5jYXBzdWxhdGVzIHNvbWUgdHlwZSBhbmFseXNpcyB0aGF0IHdvdWxkIG90aGVyd2lzZSBoYXZlIHRvIGJlXG4gKiByZXBlYXRlZCBpbiBhbGwgcGxhY2VzIHdoZXJlIGNvZGUgbmVlZHMgdG8gbWFrZSBhIGRpc3RpbmN0aW9uIG9uIHRoZSB0eXBlXG4gKiBvZiBtZXRyaWMgb2JqZWN0IHRoYXQgaXMgYmVpbmcgcGFzc2VkLlxuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuZXhwb3J0IGZ1bmN0aW9uIGRpc3BhdGNoTWV0cmljPEEsIEI+KG1ldHJpYzogSU1ldHJpYywgZm5zOiB7IHdpdGhTdGF0OiAoeDogTWV0cmljU3RhdENvbmZpZywgYzogTWV0cmljQ29uZmlnKSA9PiBBLCB3aXRoRXhwcmVzc2lvbjogKHg6IE1ldHJpY0V4cHJlc3Npb25Db25maWcsIGM6IE1ldHJpY0NvbmZpZykgPT4gQiB9KTogQSB8IEIge1xuICBjb25zdCBjb25mID0gbWV0cmljLnRvTWV0cmljQ29uZmlnKCk7XG4gIGlmIChjb25mLm1ldHJpY1N0YXQgJiYgY29uZi5tYXRoRXhwcmVzc2lvbikge1xuICAgIHRocm93IG5ldyBFcnJvcignTWV0cmljIG9iamVjdCBtdXN0IG5vdCBwcm9kdWNlIGJvdGggXFwnbWV0cmljU3RhdFxcJyBhbmQgXFwnbWF0aEV4cHJlc3Npb25cXCcnKTtcbiAgfSBlbHNlIGlmIChjb25mLm1ldHJpY1N0YXQpIHtcbiAgICByZXR1cm4gZm5zLndpdGhTdGF0KGNvbmYubWV0cmljU3RhdCwgY29uZik7XG4gIH0gZWxzZSBpZiAoY29uZi5tYXRoRXhwcmVzc2lvbikge1xuICAgIHJldHVybiBmbnMud2l0aEV4cHJlc3Npb24oY29uZi5tYXRoRXhwcmVzc2lvbiwgY29uZik7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNZXRyaWMgb2JqZWN0IG11c3QgaGF2ZSBlaXRoZXIgXFwnbWV0cmljU3RhdFxcJyBvciBcXCdtYXRoRXhwcmVzc2lvblxcJycpO1xuICB9XG59Il19
\No newline at end of file