Repository: ACloudGuru/serverless-plugin-aws-alerts (js)

Issue:
DatapointsToAlarm auto matches the EvaluationPeriod value - No way to update currently
<!--
1. Please check if an issue already exists so there are no duplicates
2. Fill out the whole template so we have a good overview on the issue
3. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
4. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a (Bug Report / Feature Proposal)

## Description

For bug reports:
* What went wrong?
When using the plugin to update the Evaluation Period it automatically set the Datapoints To Alarm equal to the value for the Evaluation Period.
* What did you expect should have happened?
I would have expected the Datapoints To Alarm value to remain 1 unless otherwise specified.
* What was the config you used?
In serverless.yml I had the `functionErrors` section with the following values:
```
functionErrors:
        period: 60
        evaluationPeriods: 5
        threshold: 1
```
* What stacktrace or error message from your provider did you see?
There were no errors, however this change would never trigger any alarms with a DatapointsToAlarm value also equal to 5.

For feature proposals:
* What is the use case that should be solved. The more detail you describe this in the easier it is to understand for us.
The value `datapointsToAlarm` needs to be added to the `definition.js` and `index.js` where the alarm is created.
* If there is additional config how would it look
Tests and Readme would also need updates with the new alarm value.

Similar or dependent issues:
* N/A

## Additional Data

* ***Serverless Framework Version***: 1.26.1
* ***Stack Trace***:
* ***Provider Error messages***:


Pull request description:
Added 'datapointsToAlarm' to definitions
## What did you implement: 
Added 'datapointsToAlarm' in the `definition.js` and `index.js` to include that value in the alarm. 
This will let everyone to manage how many datapoints they would need to trigger the alarm within their defined evaluation period.

As noted by AWS:
"When you configure Evaluation Period and Datapoints to Alarm as different values, you are setting an "M out of N" alarm. Datapoints to Alarm is ("M") and Evaluation Period is ("N"). The evaluation interval is the number of datapoints multiplied by the period. For example, if you configure 4 out of 5 datapoints with a period of 1 minute, the evaluation interval is 5 minutes. If you configure 3 out of 3 datapoints with a period of 10 minutes, the evaluation interval is 30 minutes."
Reference: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html

Closes #86

<!--
Briefly describe the feature if no issue exists for this PR
-->

## How did you implement it:
Added 'datapointsToAlarm' in the `definition.js` and 'index.js' to include that value in the alarm. I also updated the Readme, the Example, and Tests to include this new value so all documentation stays up to date.

<!--
If this is a nontrivial change please briefly describe your implementation so its easy for us to understand and review your code.
-->

## How can we verify it:
Tests were updated, I also tested this change on a local branch of one of my projects and got the expected value in CloudWatch. 
<!--
Add any applicable config, commands, screenshots or other resources
to make it easy for us to verify this works. The easier you make it for us
to review a PR, the faster we can review and merge it.

Examples:
* Screenshots - Showing the difference between your output and the master
* Other - Anything else that comes to mind to help us evaluate

In Serverless.yml under `functionErrors` I had the following setup:
```
functionErrors:
        period: 60
        evaluationPeriods: 5
        datapointsToAlarm: 1
        threshold: 1
```
And now in Cloudwatch I see the correct values of what I expect. If 1 datapoint occurs in 5 minutes an alarm will be raised.
```
Throttles >= 1 for 1 datapoints within 5 minutes
```
-->


## 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 0a2df87..842a5bc 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ custom:
         statistic: Average
         period: 300
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanOrEqualToThreshold
     alarms:
       - functionThrottles
@@ -62,6 +63,7 @@ functions:
         statistic: Minimum
         period: 60
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanOrEqualToThreshold
 ```
 
@@ -112,6 +114,7 @@ custom:
         statistic: Sum
         period: 60
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanThreshold
         pattern: '{$.level > 40}'
 ```
@@ -152,6 +155,7 @@ definitions:
     statistic: Sum
     period: 60
     evaluationPeriods: 1
+    datapointsToAlarm: 1
     comparisonOperator: GreaterThanOrEqualToThreshold
     treatMissingData: missing
   functionErrors:
@@ -161,6 +165,7 @@ definitions:
     statistic: Sum
     period: 60
     evaluationPeriods: 1
+    datapointsToAlarm: 1
     comparisonOperator: GreaterThanOrEqualToThreshold
     treatMissingData: missing
   functionDuration:
@@ -179,6 +184,7 @@ definitions:
     statistic: Sum
     period: 60
     evaluationPeriods: 1
+    datapointsToAlarm: 1
     comparisonOperator: GreaterThanOrEqualToThreshold
     treatMissingData: missing
 ```
@@ -196,6 +202,7 @@ definitions:
     statistic: 'p95'
     period: 60
     evaluationPeriods: 1
+    datapointsToAlarm: 1
     comparisonOperator: GreaterThanThreshold
     treatMissingData: missing
 ```
diff --git a/example/serverless.yml b/example/serverless.yml
index c629aec..30c50dc 100644
--- a/example/serverless.yml
+++ b/example/serverless.yml
@@ -47,6 +47,7 @@ custom:
         statistic: Average
         period: 300
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanThreshold
     global:
       - functionThrottles
@@ -70,6 +71,7 @@ functions:
         statistic: Minimum
         period: 60
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanThreshold
     events:
       - http:
@@ -87,6 +89,7 @@ functions:
         statistic: Sum
         period: 60
         evaluationPeriods: 1
+        datapointsToAlarm: 1
         comparisonOperator: GreaterThanThreshold
         pattern: '{$.level > 40}'
     events:
diff --git a/src/defaults/definitions.js b/src/defaults/definitions.js
index c38a34e..06c4e77 100644
--- a/src/defaults/definitions.js
+++ b/src/defaults/definitions.js
@@ -10,6 +10,7 @@ module.exports = {
     statistic: 'Sum',
     period: 60,
     evaluationPeriods: 1,
+    datapointsToAlarm: 1,
     comparisonOperator: 'GreaterThanOrEqualToThreshold',
   },
   functionErrors: {
@@ -19,6 +20,7 @@ module.exports = {
     statistic: 'Sum',
     period: 60,
     evaluationPeriods: 1,
+    datapointsToAlarm: 1,
     comparisonOperator: 'GreaterThanOrEqualToThreshold',
   },
   functionDuration: {
@@ -28,6 +30,7 @@ module.exports = {
     statistic: 'Average',
     period: 60,
     evaluationPeriods: 1,
+    datapointsToAlarm: 1,
     comparisonOperator: 'GreaterThanOrEqualToThreshold',
   },
   functionThrottles: {
@@ -37,6 +40,7 @@ module.exports = {
     statistic: 'Sum',
     period: 60,
     evaluationPeriods: 1,
+    datapointsToAlarm: 1,
     comparisonOperator: 'GreaterThanOrEqualToThreshold',
   }
 };
diff --git a/src/index.js b/src/index.js
index f406ee9..99abf72 100644
--- a/src/index.js
+++ b/src/index.js
@@ -116,6 +116,7 @@ class AlertsPlugin {
         Threshold: definition.threshold,
         Period: definition.period,
         EvaluationPeriods: definition.evaluationPeriods,
+        DatapointsToAlarm: definition.datapointsToAlarm,
         ComparisonOperator: definition.comparisonOperator,
         OKActions: okActions,
         AlarmActions: alarmActions,
@@ -269,8 +270,8 @@ class AlertsPlugin {
     const dashboardTemplates = this.getDashboardTemplates(configDashboards);
 
     const functions = this.serverless.service
-                          .getAllFunctions()
-                          .map(functionName => ({ name: functionName }));
+      .getAllFunctions()
+      .map(functionName => ({ name: functionName }));
 
     const cf = _.chain(dashboardTemplates)
       .uniq()


Test patch:
diff --git a/src/index.test.js b/src/index.test.js
index 037e636..b4a56c2 100644
--- a/src/index.test.js
+++ b/src/index.test.js
@@ -179,6 +179,7 @@ describe('#index', function () {
             statistic: 'Maximum',
             period: 300,
             evaluationPeriods: 1,
+            datapointsToAlarm: 1,
             comparisonOperator: 'GreaterThanOrEqualToThreshold',
           },
           customDefinition: {
@@ -188,6 +189,7 @@ describe('#index', function () {
             statistic: 'Minimum',
             period: 120,
             evaluationPeriods: 2,
+            datapointsToAlarm: 1,
             comparisonOperator: 'GreaterThanOrEqualToThreshold',
           }
         }
@@ -204,6 +206,7 @@ describe('#index', function () {
           statistic: 'Sum',
           period: 60,
           evaluationPeriods: 1,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         },
         functionErrors: {
@@ -213,6 +216,7 @@ describe('#index', function () {
           statistic: 'Maximum',
           period: 300,
           evaluationPeriods: 1,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         },
         functionDuration: {
@@ -222,6 +226,7 @@ describe('#index', function () {
           statistic: 'Average',
           period: 60,
           evaluationPeriods: 1,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         },
         functionThrottles: {
@@ -231,6 +236,7 @@ describe('#index', function () {
           statistic: 'Sum',
           period: 60,
           evaluationPeriods: 1,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         },
         customDefinition: {
@@ -240,6 +246,7 @@ describe('#index', function () {
           statistic: 'Minimum',
           period: 120,
           evaluationPeriods: 2,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         }
       });
@@ -256,6 +263,7 @@ describe('#index', function () {
           statistic: 'Minimum',
           period: 120,
           evaluationPeriods: 2,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         }
       },
@@ -300,6 +308,7 @@ describe('#index', function () {
         statistic: 'Minimum',
         period: 120,
         evaluationPeriods: 2,
+        datapointsToAlarm: 1,
         comparisonOperator: 'GreaterThanOrEqualToThreshold',
       }]);
     });
@@ -316,6 +325,7 @@ describe('#index', function () {
           statistic: 'Minimum',
           period: 120,
           evaluationPeriods: 2,
+          datapointsToAlarm: 1,
           comparisonOperator: 'GreaterThanOrEqualToThreshold',
         }]
       }, config, definitions);
@@ -328,6 +338,7 @@ describe('#index', function () {
         statistic: 'Minimum',
         period: 120,
         evaluationPeriods: 2,
+        datapointsToAlarm: 1,
         comparisonOperator: 'GreaterThanOrEqualToThreshold',
       }]);
     });
@@ -453,6 +464,7 @@ describe('#index', function () {
             Statistic: 'Sum',
             Period: 60,
             EvaluationPeriods: 1,
+            DatapointsToAlarm: 1,
             ComparisonOperator: 'GreaterThanOrEqualToThreshold',
             AlarmActions: [],
             OKActions: [],
@@ -477,6 +489,7 @@ describe('#index', function () {
             statistic: 'Sum',
             period: 60,
             evaluationPeriods: 1,
+            datapointsToAlarm: 1,
             comparisonOperator: 'GreaterThanOrEqualToThreshold',
             pattern: '{$.level > 40}'
           }
@@ -501,6 +514,7 @@ describe('#index', function () {
             Statistic: 'Sum',
             Period: 60,
             EvaluationPeriods: 1,
+            DatapointsToAlarm: 1,
             ComparisonOperator: 'GreaterThanOrEqualToThreshold',
             OKActions: [],
             AlarmActions: [],