From 3e7ea5a1918e46a60962a543251f12c5c75a18e7 Mon Sep 17 00:00:00 2001 From: Kevin Tardif Date: Tue, 13 Aug 2019 15:39:32 -0400 Subject: [PATCH 1/4] Added log.level setting to customize AWS API Gateway log level --- docs/providers/aws/events/apigateway.md | 13 ++++++ .../events/apiGateway/lib/hack/updateStage.js | 14 +++++- .../apiGateway/lib/hack/updateStage.test.js | 45 ++++++++++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index c6a06d435..3aaffb62f 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -1507,3 +1507,16 @@ provider: restApi: format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp" }' ``` + +The default API Gateway log level will be INFO. You can change this to error with the following: + +```yml +# serverless.yml +provider: + name: aws + logs: + restApi: + level: ERROR +``` + +Valid values are INFO, ERROR. diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js index 8f5d2834a..0a62d8cea 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js @@ -16,6 +16,8 @@ const defaultApiGatewayLogFormat = [ 'protocol: $context.protocol', 'responseLength: $context.responseLength', ].join(', '); +const defaultApiGatewayLogLevel = 'INFO'; +const apiGatewayValidLogLevels = ['INFO', 'ERROR']; // NOTE --> Keep this file in sync with ../stage.js @@ -23,6 +25,8 @@ const defaultApiGatewayLogFormat = [ // Stage resource (see https://github.com/serverless/serverless/pull/5692#issuecomment-467849311 for more information). module.exports = { + defaultApiGatewayLogLevel, + apiGatewayValidLogLevels, updateStage() { // this array is used to gather all the patch operations we need to // perform on the stage @@ -191,6 +195,14 @@ function handleLogs() { logFormat = logs.format; } + let level = defaultApiGatewayLogLevel; + if (logs.level) { + level = logs.level; + if (!apiGatewayValidLogLevels.includes(level)) { + throw new Error(`provider.logs.restApi.level is set to an invalid value. Support values are ${apiGatewayValidLogLevels.join(', ')}, got ${level}.`) + } + } + const destinationArn = { op: 'replace', path: '/accessLogSettings/destinationArn', @@ -202,7 +214,7 @@ function handleLogs() { value: logFormat, }; dataTrace = { op: 'replace', path: '/*/*/logging/dataTrace', value: 'true' }; - logLevel = { op: 'replace', path: '/*/*/logging/loglevel', value: 'INFO' }; + logLevel = { op: 'replace', path: '/*/*/logging/loglevel', value: level }; operations = [destinationArn, format, dataTrace, logLevel]; } diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js index 1c6e79297..b67c14446 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js @@ -8,9 +8,10 @@ const sinon = require('sinon'); const _ = require('lodash'); const Serverless = require('../../../../../../../../Serverless'); const AwsProvider = require('../../../../../../provider/awsProvider'); -const updateStage = require('./updateStage').updateStage; +const {updateStage, apiGatewayValidLogLevels, defaultApiGatewayLogLevel} = require('./updateStage'); chai.use(require('sinon-chai')); +chai.use(require('chai-as-promised')); const { expect } = chai; @@ -389,4 +390,46 @@ describe('#updateStage()', () => { }); }); }); + + function checkLogLevel(setLevel, expectedLevel) { + if (setLevel) { + context.state.service.provider.logs = { + restApi: { + level: setLevel, + }, + }; + } + else { + context.state.service.provider.logs = { + restApi: true, + }; + } + + return updateStage.call(context).then(() => { + const patchOperation = {op: 'replace', path: '/*/*/logging/loglevel', value: expectedLevel}; + + const patchOperations = providerRequestStub.args[2][2].patchOperations; + expect(patchOperations).to.include.deep.members([patchOperation]); + }); + } + + it('should use the default log level if no log level is given', () => { + return checkLogLevel(null, defaultApiGatewayLogLevel); + }); + + apiGatewayValidLogLevels.forEach((logLevel) => { + it(`should update the stage with a custom APIGW log level if given ${logLevel}`, () => { + return checkLogLevel(logLevel, logLevel); + }); + }); + + it('should reject a custom APIGW log level if value is invalid', () => { + context.state.service.provider.logs = { + restApi: { + level: 'INVALID', + }, + }; + + return expect(updateStage.call(context)).to.be.rejectedWith('invalid value'); + }); }); From 5332dfdf396ba58b8fce63ce28b0f8f1474d714a Mon Sep 17 00:00:00 2001 From: Kevin Tardif Date: Wed, 14 Aug 2019 08:30:45 -0400 Subject: [PATCH 2/4] Updated AWS serverless.yml reference to include logs.level and format documentation --- docs/providers/aws/guide/serverless.yml.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/providers/aws/guide/serverless.yml.md b/docs/providers/aws/guide/serverless.yml.md index c9e6d573f..d108e732c 100644 --- a/docs/providers/aws/guide/serverless.yml.md +++ b/docs/providers/aws/guide/serverless.yml.md @@ -130,7 +130,9 @@ provider: apiGateway: true lambda: true # Optional, can be true (true equals 'Active'), 'Active' or 'PassThrough' logs: - restApi: true # Optional configuration which specifies if API Gateway logs are used + restApi: # Optional configuration which specifies if API Gateway logs are used. This can either be set to true to use defaults, or configured via subproperties. + format: 'requestId: $context.requestId' # Optional configuration which specifies the log format to use. + level: INFO # Optional configuration which specifies the log level to use. May be either INFO or ERROR. websocket: true # Optional configuration which specifies if Websockets logs are used package: # Optional deployment packaging configuration From bea1caec265ecc31495b2587eb90adaf189c8236 Mon Sep 17 00:00:00 2001 From: Kevin Tardif Date: Wed, 14 Aug 2019 08:47:48 -0400 Subject: [PATCH 3/4] Updated formatting --- .../events/apiGateway/lib/hack/updateStage.js | 6 +++++- .../events/apiGateway/lib/hack/updateStage.test.js | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js index 0a62d8cea..4ca764287 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js @@ -199,7 +199,11 @@ function handleLogs() { if (logs.level) { level = logs.level; if (!apiGatewayValidLogLevels.includes(level)) { - throw new Error(`provider.logs.restApi.level is set to an invalid value. Support values are ${apiGatewayValidLogLevels.join(', ')}, got ${level}.`) + throw new Error( + `provider.logs.restApi.level is set to an invalid value. Support values are ${apiGatewayValidLogLevels.join( + ', ' + )}, got ${level}.` + ); } } diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js index b67c14446..f5c23fb83 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.test.js @@ -8,7 +8,11 @@ const sinon = require('sinon'); const _ = require('lodash'); const Serverless = require('../../../../../../../../Serverless'); const AwsProvider = require('../../../../../../provider/awsProvider'); -const {updateStage, apiGatewayValidLogLevels, defaultApiGatewayLogLevel} = require('./updateStage'); +const { + updateStage, + apiGatewayValidLogLevels, + defaultApiGatewayLogLevel, +} = require('./updateStage'); chai.use(require('sinon-chai')); chai.use(require('chai-as-promised')); @@ -398,15 +402,14 @@ describe('#updateStage()', () => { level: setLevel, }, }; - } - else { + } else { context.state.service.provider.logs = { restApi: true, }; } return updateStage.call(context).then(() => { - const patchOperation = {op: 'replace', path: '/*/*/logging/loglevel', value: expectedLevel}; + const patchOperation = { op: 'replace', path: '/*/*/logging/loglevel', value: expectedLevel }; const patchOperations = providerRequestStub.args[2][2].patchOperations; expect(patchOperations).to.include.deep.members([patchOperation]); @@ -417,7 +420,7 @@ describe('#updateStage()', () => { return checkLogLevel(null, defaultApiGatewayLogLevel); }); - apiGatewayValidLogLevels.forEach((logLevel) => { + apiGatewayValidLogLevels.forEach(logLevel => { it(`should update the stage with a custom APIGW log level if given ${logLevel}`, () => { return checkLogLevel(logLevel, logLevel); }); From cf390d5f887446254d29d37ee91a3ef5cf1ae1d2 Mon Sep 17 00:00:00 2001 From: Kevin Tardif Date: Wed, 14 Aug 2019 10:20:49 -0400 Subject: [PATCH 4/4] Updated valid apigw log levels to use a set, using ServerlessError instead of Error --- .../events/apiGateway/lib/hack/updateStage.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js index 4ca764287..710b43b46 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/updateStage.js @@ -2,6 +2,7 @@ const _ = require('lodash'); const BbPromise = require('bluebird'); +const ServerlessError = require('../../../../../../../../classes/Error').ServerlessError; const isRestApiId = RegExp.prototype.test.bind(/^[a-z0-9]{3,}$/); const defaultApiGatewayLogFormat = [ @@ -17,7 +18,7 @@ const defaultApiGatewayLogFormat = [ 'responseLength: $context.responseLength', ].join(', '); const defaultApiGatewayLogLevel = 'INFO'; -const apiGatewayValidLogLevels = ['INFO', 'ERROR']; +const apiGatewayValidLogLevels = new Set(['INFO', 'ERROR']); // NOTE --> Keep this file in sync with ../stage.js @@ -198,11 +199,11 @@ function handleLogs() { let level = defaultApiGatewayLogLevel; if (logs.level) { level = logs.level; - if (!apiGatewayValidLogLevels.includes(level)) { - throw new Error( - `provider.logs.restApi.level is set to an invalid value. Support values are ${apiGatewayValidLogLevels.join( - ', ' - )}, got ${level}.` + if (!apiGatewayValidLogLevels.has(level)) { + throw new ServerlessError( + `provider.logs.restApi.level is set to an invalid value. Support values are ${Array.from( + apiGatewayValidLogLevels + ).join(', ')}, got ${level}.` ); } }