Support for CloudWatch Metric Math Alarms#44
Support for CloudWatch Metric Math Alarms#44bobwilkinson20 wants to merge 3 commits intoassertible:masterfrom
Conversation
index.js
Outdated
| var metricName = message.Trigger.MetricName; | ||
| var trigger = message.Trigger; | ||
| var alarmExpression; | ||
| if (typeof trigger.MetricName === "undefined") { |
There was a problem hiding this comment.
If trigger.MetricName and trigger.Metrics are mutually exclusive, it may improve readability to say "If this trigger has multiple metrics, use them" instead of "If this trigger doesn't have a single metric, use multiple." if (typeof trigger.Metrics === 'object') will determine if trigger.Metrics is an array.
There was a problem hiding this comment.
There's also Array.isArray(trigger.Metrics) instead of checking typeof. While it is a part of the ES5 spec, older browser has spotty implementations. NodeJS should not have a problem with it. If you find that ES6 is acceptable for this file, Array.isArray should be acceptable as well.
There was a problem hiding this comment.
changed to if (typeof trigger.Metrics === 'object')
index.js
Outdated
|
|
||
| // first build a dictionary mapping metric ids to metric name and statistic | ||
| var sourceMetrics = {}; | ||
| for (const metric of trigger.Metrics.slice(1)) { |
There was a problem hiding this comment.
const and for...of loops are ES6, but the rest of this file seems to be using ES5 (e.g. var instead of let or const). I'd make sure ES6 is supported and that ES5 is not otherwise a requirement. It is odd to see both in one file.
As ES5, this would be:
var triggerMetricsLength = trigger.Metrics.length;
for (var i = 1; i < triggerMetricsLength; i++) {
var metric = trigger.Metrics[i];
// ...
}There was a problem hiding this comment.
combined this change with below recommendation
index.js
Outdated
|
|
||
| // now replace each instance of the metric id in the alarm expression | ||
| alarmExpression = trigger.Metrics[0].Expression; | ||
| for (var metricid in sourceMetrics) { |
There was a problem hiding this comment.
for...in loops should be avoided. If you are just trying to get the metric.Ids, this loop can probably be a copy of or merged with the previous.
alarmExpression = trigger.Metrics[0].Expression;
var triggerMetricsLength = trigger.Metrics.length;
for (var i = 1; i < triggerMetricsLength; i++) {
var metric = trigger.Metrics[i];
alarmExpression = alarmExpression.replace(
new RegExp(metric.Id, 'g'),
metric.MetricStat.Stat + ':' + metric.MetricStat.Metric.MetricName
);
}There was a problem hiding this comment.
great suggestion - adopted this logic
index.js
Outdated
| // now replace each instance of the metric id in the alarm expression | ||
| alarmExpression = trigger.Metrics[0].Expression; | ||
| for (var metricid in sourceMetrics) { | ||
| alarmExpression = alarmExpression.replace(new RegExp(metricid,"g"),sourceMetrics[metricid]); |
There was a problem hiding this comment.
If metric.Id is not intended to be a regular expression itself, it should probably be escaped. As is, a malicious user can submit a custom, unsanitized regular expression as input, which may produce undesirable effects if we parse it.
function sanitizeStringForRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
alarmExpression = alarmExpression.replace(
new RegExp(sanitizeStringForRegExp(metricid), 'g'),
sourceMetrics[metricid]
);Source: Stack Overflow
There was a problem hiding this comment.
incorporated escape-string-regexp package which implements the equivalent of sanitizeStringForRegExp above.
The existing CloudWatch handler did not support alarm notifications for metric math alarms (aka math expression alarms).