Skip to content

Commit d9e510e

Browse files
author
Artificer Entertainment
committed
Initial commit.
1 parent 2fc8f2c commit d9e510e

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

README.md

+18
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
11
# serverless-plugin-log-retention
22
Control the retention of your serverless function's cloudwatch logs.
3+
4+
## Usage example
5+
`serverless.yml`
6+
7+
```yml
8+
service: sample
9+
10+
plugins:
11+
- serverless-plugin-log-retention
12+
13+
provider:
14+
logRetentionInDays: 30 # used to set a global value for all functions
15+
16+
functions:
17+
function1:
18+
function2:
19+
logRetentionInDays: 10 # set the retention for specific log group
20+
```

add-log-retention.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use strict';
2+
3+
const nco = require('nco');
4+
const semver = require('semver');
5+
6+
const validRetentionInDays = [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653];
7+
8+
class AwsAddLogRetention {
9+
constructor(serverless, options) {
10+
if(!semver.satisfies(serverless.version, '>= 1.20.2')) {
11+
throw new Error('serverless-plugin-log-retention requires serverless 1.20.2 or higher');
12+
}
13+
14+
this.serverless = serverless;
15+
this.options = options;
16+
this.provider = this.serverless.getProvider('aws');
17+
this.hooks = {
18+
'before:deploy:createDeploymentArtifacts': this.beforeDeploy.bind(this),
19+
};
20+
}
21+
22+
sanitizeRetentionValue(inputValue) {
23+
const value = Number(inputValue);
24+
if(Number.isInteger(value) && validRetentionInDays.includes(value)) {
25+
return value;
26+
} else {
27+
throw new Error(`RetentionInDays value must be one of ${validRetentionInDays}`);
28+
}
29+
}
30+
31+
addLogRetentionForFunctions(globalLogRetentionInDays) {
32+
const service = this.serverless.service;
33+
if(typeof service.functions !== 'object') {
34+
return;
35+
}
36+
37+
const resources = nco(service.resources, {});
38+
resources.Resources = nco(resources.Resources, {});
39+
40+
Object.keys(service.functions).forEach(functionName => {
41+
const localLogRentationInDays = nco(service.functions[functionName].logRetentionInDays, null);
42+
if(localLogRentationInDays === null && globalLogRetentionInDays === null) {
43+
return;
44+
}
45+
const functionLogRetentionInDays = localLogRentationInDays === null ? globalLogRetentionInDays : sanitizeRetentionValue(localLogRentationInDays);
46+
const logGroupLogicalId = this.provider.naming.getLogGroupLogicalId(functionName);
47+
48+
const resource = {
49+
Type: 'AWS::Logs::LogGroup',
50+
Properties: {
51+
RetentionInDays: functionLogRetentionInDays
52+
}
53+
};
54+
resources.Resources[logGroupLogicalId] = resource;
55+
});
56+
}
57+
58+
beforeDeploy() {
59+
const service = this.serverless.service;
60+
const globalLogRetentionInDays = service.provider && service.provider.logRetentionInDays
61+
? sanitizeRetentionValue(service.provider.logRetentionInDays)
62+
: null;
63+
this.addLogRetentionForFunctions(globalLogRetentionInDays);
64+
}
65+
}
66+
67+
module.exports = AwsAddLogRetention;

package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "serverless-plugin-log-retention",
3+
"version": "1.0.0",
4+
"description": "Control the retention of your function's cloudwatch logs.",
5+
"main": "add-log-retention.js",
6+
"scripts": {
7+
"test": "nyc --reporter=lcov --reporter=text mocha"
8+
},
9+
"keywords": [
10+
"serverless",
11+
"plugin",
12+
"log",
13+
"retention"
14+
],
15+
"author": "Jim Walkoski",
16+
"license": "MIT",
17+
"dependencies": {
18+
"nco": "1.0.1",
19+
"semver": "5.4.1"
20+
},
21+
"devDependencies": {
22+
"chai": "4.1.2",
23+
"mocha": "4.0.1",
24+
"nyc": "11.3.0",
25+
"sinon": "4.1.2"
26+
}
27+
}

test/add-log-retention.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
const expect = require('chai').expect;
4+
const sinon = require('sinon');
5+
6+
const AwsAddLogRetention = require('../add-log-retention');
7+
8+
function createTestInstance(options) {
9+
options = options || {};
10+
return new AwsAddLogRetention({
11+
version: options.version || '1.20.2',
12+
service: {
13+
provider: options.provider || {},
14+
functions: options.functions,
15+
resources: options.resources ? { Resources: options.resources } : undefined
16+
},
17+
getProvider: () => {
18+
return {
19+
naming: {
20+
getLogGroupLogicalId(functionName) {
21+
return `${functionName.charAt(0).toUpperCase()}${functionName.slice(1)}LogGroup`; //TODO: dash/underscore replacement?
22+
}
23+
}
24+
}
25+
}
26+
}, {});
27+
}
28+
29+
describe('serverless-plugin-log-retention', function() {
30+
describe('#constructor', function() {
31+
it('should throw on older version', function() {
32+
expect(() => createTestInstance({version: '1.20.1'}))
33+
.to.throw('serverless-plugin-log-retention requires serverless 1.20.2 or higher');
34+
});
35+
36+
it('should create hooks', function() {
37+
const instance = createTestInstance();
38+
expect(instance)
39+
.to.have.property('hooks')
40+
.that.has.all.keys('before:deploy:createDeploymentArtifacts');
41+
42+
const stub = sinon.stub(instance, 'addLogRetentionForFunctions');
43+
instance.hooks['before:deploy:createDeploymentArtifacts']();
44+
45+
sinon.assert.calledOnce(stub);
46+
});
47+
})
48+
49+
});

0 commit comments

Comments
 (0)