Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for CloudWatch Metric Math Alarms #44

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

bobwilkinson20
Copy link

The existing CloudWatch handler did not support alarm notifications for metric math alarms (aka math expression alarms).

index.js Outdated
var metricName = message.Trigger.MetricName;
var trigger = message.Trigger;
var alarmExpression;
if (typeof trigger.MetricName === "undefined") {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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];
  // ...
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
  );
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorporated escape-string-regexp package which implements the equivalent of sanitizeStringForRegExp above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants