Repository: ACloudGuru/serverless-plugin-aws-alerts
Pull request #37 (2017-07-18 14:40:44)

add support for the CloudFormation value ExtendedStatistic
## What did you implement:

Closes https://github.com/ACloudGuru/serverless-plugin-aws-alerts/issues/33

In CloudFormation you can either provide `Statistic` or `ExtendedStatistic`. We use `Statistic` if the value is part of the predefined value and if not fall back to `ExtendedStatistic`. I didn't check for `p{d}` regex, but this could be added to improve warnings to the user …

## How did you implement it:

Updated the `getAlarmCloudFormation` function.

## How can we verify it:

I actually only tested the config manually before and then relied on the test.

## Todos:

- [x] Write tests
- [x] Write documentation
- [x] Fix linting errors
- [x] Provide verification config/commands/resources




Patch:
diff --git a/README.md b/README.md
index e270906..ce7ace0 100644
--- a/README.md
+++ b/README.md
@@ -164,6 +164,23 @@ definitions:
     treatMissingData: missing
 ```
 
+## Using Percentile Statistic for a Metric
+
+Statistic not only supports SampleCount, Average, Sum, Minimum or Maximum as defined in CloudFormation [here](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html#cfn-cloudwatch-alarms-statistic), but also percentiles. This is possible by leveraging  [ExtendedStatistic](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html#cfn-cloudwatch-alarms-extendedstatistic) under the hood. This plugin will automatically choose the correct key for you. See an example below:
+
+```yaml
+definitions:
+  functionDuration:
+    namespace: 'AWS/Lambda'
+    metric: Duration
+    threshold: 100
+    statistic: 'p95'
+    period: 60
+    evaluationPeriods: 1
+    comparisonOperator: GreaterThanThreshold
+    treatMissingData: missing
+```
+
 ## License
 
 MIT © [A Cloud Guru](https://acloud.guru/)
diff --git a/src/index.js b/src/index.js
index b31ab41..be5c355 100644
--- a/src/index.js
+++ b/src/index.js
@@ -107,14 +107,13 @@ class Plugin {
 
     const treatMissingData = definition.treatMissingData ? definition.treatMissingData : 'missing';
 
-    return {
+    const alarm = {
       Type: 'AWS::CloudWatch::Alarm',
       Properties: {
         Namespace: namespace,
         MetricName: metricName,
         AlarmDescription: definition.description,
         Threshold: definition.threshold,
-        Statistic: definition.statistic,
         Period: definition.period,
         EvaluationPeriods: definition.evaluationPeriods,
         ComparisonOperator: definition.comparisonOperator,
@@ -125,6 +124,14 @@ class Plugin {
         TreatMissingData: treatMissingData,
       }
     };
+
+    const statisticValues = [ 'SampleCount', 'Average', 'Sum', 'Minimum', 'Maximum'];
+    if (_.includes(statisticValues, definition.statistic)) {
+      alarm.Properties.Statistic = definition.statistic
+    } else {
+      alarm.Properties.ExtendedStatistic = definition.statistic
+    }
+    return alarm;
   }
 
   getSnsTopicCloudFormation(topicName, notifications) {


Test patch:
diff --git a/src/index.test.js b/src/index.test.js
index 25c3ed3..98ba857 100644
--- a/src/index.test.js
+++ b/src/index.test.js
@@ -662,5 +662,53 @@ describe('#index', function () {
         }
       });
     });
+
+    it('should user the CloudFormation value ExtendedStatistic for p values', () => {
+      const alertTopics = {
+        ok: 'ok-topic',
+        alarm: 'alarm-topic',
+        insufficientData: 'insufficientData-topic',
+      };
+
+      const definition = {
+        description: 'An error alarm',
+        namespace: 'AWS/Lambda',
+        metric: 'Errors',
+        threshold: 1,
+        statistic: 'p95',
+        period: 300,
+        evaluationPeriods: 1,
+        comparisonOperator: 'GreaterThanThreshold',
+        treatMissingData: 'breaching',
+      };
+
+      const functionRef = 'func-ref';
+
+      const cf = plugin.getAlarmCloudFormation(alertTopics, definition, functionRef);
+
+      expect(cf).toEqual({
+        Type: 'AWS::CloudWatch::Alarm',
+        Properties: {
+          AlarmDescription: definition.description,
+          Namespace: definition.namespace,
+          MetricName: definition.metric,
+          Threshold: definition.threshold,
+          ExtendedStatistic: definition.statistic,
+          Period: definition.period,
+          EvaluationPeriods: definition.evaluationPeriods,
+          ComparisonOperator: definition.comparisonOperator,
+          OKActions: ['ok-topic'],
+          AlarmActions: ['alarm-topic'],
+          InsufficientDataActions: ['insufficientData-topic'],
+          Dimensions: [{
+            Name: 'FunctionName',
+            Value: {
+              Ref: functionRef,
+            }
+          }],
+          TreatMissingData: 'breaching',
+        }
+      });
+    });
   })
 });