Repository: serverless/serverless (JavaScript)
Date: 2017-12-19 15:17:40+00:00
Task type: Feature

Issue:
Add a new property which specify RetentionInDays with CloudWathcLogs to serverless.yml
<!--
1. If you have a question and not a bug/feature request please ask it at http://forum.serverless.com
2. Please check if an issue already exists so there are no duplicates
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a (Feature Proposal)

## Description
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.

Currently, RetentionInDays with CloudWathcLogs is 30 days as default. It can be overridden by writing up a new value within resources section of serverless.yml.
https://serverless.com/framework/docs/providers/aws/guide/resources/#override-aws-cloudformation-resource

However, It's too much hassle to override it every time you add a new function. 
In many cases, it is overridden since 30 days is too long.

My suggestion is creating a new property which you can specify default value for RetentionInDays.

* If there is additional config how would it look

it would be good to something like this within serverless.yml

```
provider
  retentionInDays: 5
```




Issue discussion:
Wonderful idea. However, I would name it
```
provider
  logRetentionInDays: 5
```
with a prepended "log" to make clear that it is for the log streams.
Thanks @HyperBrain for the feedback.

>with a prepended "log" to make clear that it is for the log streams.

Yup. that’s better :+1: 


Solution patch:
diff --git a/docs/providers/aws/guide/serverless.yml.md b/docs/providers/aws/guide/serverless.yml.md
index 2bb376af946..30f1c137446 100644
--- a/docs/providers/aws/guide/serverless.yml.md
+++ b/docs/providers/aws/guide/serverless.yml.md
@@ -31,6 +31,7 @@ provider:
   profile: production # The default profile to use with this service
   memorySize: 512 # Overwrite the default memory size. Default is 1024
   timeout: 10 # The default is 6 seconds. Note: API Gateway current maximum is 30 seconds
+  logRetentionInDays: 14 # Set the default RetentionInDays for a CloudWatch LogGroup
   deploymentBucket:
     name: com.serverless.${self:provider.region}.deploys # Deployment bucket name. Default is generated by the framework
     serverSideEncryption: AES256 # when using server-side encryption
diff --git a/lib/plugins/aws/package/lib/mergeIamTemplates.js b/lib/plugins/aws/package/lib/mergeIamTemplates.js
index 7276853b002..a17e2dffd8a 100644
--- a/lib/plugins/aws/package/lib/mergeIamTemplates.js
+++ b/lib/plugins/aws/package/lib/mergeIamTemplates.js
@@ -29,6 +29,18 @@ module.exports = {
           },
         },
       };
+
+      if (_.has(this.serverless.service.provider, 'logRetentionInDays')) {
+        if (_.isInteger(this.serverless.service.provider.logRetentionInDays) &&
+        this.serverless.service.provider.logRetentionInDays > 0) {
+          newLogGroup[logGroupLogicalId].Properties.RetentionInDays
+            = this.serverless.service.provider.logRetentionInDays;
+        } else {
+          const errorMessage = 'logRetentionInDays should be an integer over 0';
+          throw new this.serverless.classes.Error(errorMessage);
+        }
+      }
+
       _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
         newLogGroup);
     });


Test patch:
diff --git a/lib/plugins/aws/package/lib/mergeIamTemplates.test.js b/lib/plugins/aws/package/lib/mergeIamTemplates.test.js
index f5c9c6be7a9..1407989251f 100644
--- a/lib/plugins/aws/package/lib/mergeIamTemplates.test.js
+++ b/lib/plugins/aws/package/lib/mergeIamTemplates.test.js
@@ -238,6 +238,41 @@ describe('#mergeIamTemplates()', () => {
     });
   });
 
+  it('should add RetentionInDays to a CloudWatch LogGroup resource if logRetentionInDays is given'
+  , () => {
+    awsPackage.serverless.service.provider.logRetentionInDays = 5;
+    const normalizedName = awsPackage.provider.naming.getLogGroupLogicalId(functionName);
+    return awsPackage.mergeIamTemplates().then(() => {
+      expect(awsPackage.serverless.service.provider.compiledCloudFormationTemplate
+        .Resources[normalizedName]
+      ).to.deep.equal(
+        {
+          Type: 'AWS::Logs::LogGroup',
+          Properties: {
+            LogGroupName: awsPackage.provider.naming.getLogGroupName(functionName),
+            RetentionInDays: 5,
+          },
+        }
+      );
+    });
+  });
+
+  it('should throw error if RetentionInDays is 0 or not an integer'
+  , () => {
+    awsPackage.serverless.service.provider.logRetentionInDays = 0;
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+    awsPackage.serverless.service.provider.logRetentionInDays = 'string';
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+    awsPackage.serverless.service.provider.logRetentionInDays = [];
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+    awsPackage.serverless.service.provider.logRetentionInDays = {};
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+    awsPackage.serverless.service.provider.logRetentionInDays = undefined;
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+    awsPackage.serverless.service.provider.logRetentionInDays = null;
+    expect(() => awsPackage.mergeIamTemplates()).to.throw('should be an integer');
+  });
+
   it('should add a CloudWatch LogGroup resource if all functions use custom roles', () => {
     awsPackage.serverless.service.functions[functionName].role = 'something';
     awsPackage.serverless.service.functions = {