diff --git a/README.md b/README.md index 9c06395..3ae59a3 100644 --- a/README.md +++ b/README.md @@ -812,6 +812,7 @@ Logging can be enabled by setting the `logger` option to `true` when creating th | level | `string` | Minimum logging level to send logs for. See [Logging Levels](#logging-levels). | `info` | | levels | `object` | Key/value pairs of custom log levels and their priority. See [Custom Logging Levels](#custom-logging-levels). | | | messageKey | `string` | Sets the JSON property name of the log "message". | `msg` | +| multiValue | `boolean` | Enables multi-value support for querystrings. If enabled, the `qs` parameter will return all values as `array`s and will include multiple values if they exist. | `false` | | nested | `boolean` | Enables/disables nesting of JSON logs for serializer data. See [Serializers](#serializers). | `false` | | timestamp | `boolean` or `function` | By default, timestamps will return the epoch time in milliseconds. A value of `false` disables log timestamps. A function that returns a value can be used to override the default format. | `true` | | sampling | `object` | Enables log sampling for periodic request tracing. See [Sampling](#sampling). | | diff --git a/lib/logger.js b/lib/logger.js index 6137357..3dec9a1 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -53,6 +53,8 @@ exports.config = (config,levels) => { let access = cfg.access === true ? true : cfg.access === 'never' ? 'never' : false // create access logs let detail = cfg.detail === true ? true : false // add req/res detail to all logs + let multiValue = cfg.multiValue === true ? true : false // return qs as multiValue + let defaults = { req: req => { return { @@ -62,7 +64,8 @@ exports.config = (config,levels) => { device: req.clientType, country: req.clientCountry, version: req.version, - qs: Object.keys(req.query).length > 0 ? req.query : undefined + qs: multiValue ? (Object.keys(req.multiValueQuery).length > 0 ? req.multiValueQuery : undefined) + : (Object.keys(req.query).length > 0 ? req.query : undefined) } }, res: () => { diff --git a/test/log.js b/test/log.js index 9db499c..8e747df 100644 --- a/test/log.js +++ b/test/log.js @@ -4,6 +4,7 @@ const expect = require('chai').expect // Assertion library // Init API instance const api_default = require('../index')({ logger: true }) // default logger +const api_multi = require('../index')({ logger: { multiValue: true } }) const api_customLevel = require('../index')({ version: 'v1.0', logger: { level: 'debug' } }) const api_disableLevel = require('../index')({ version: 'v1.0', logger: { level: 'none' } }) const api_customMsgKey = require('../index')({ version: 'v1.0', logger: { messageKey: 'customKey' } }) @@ -96,6 +97,16 @@ api_default.get('/', (req,res) => { res.send('done') }) +api_multi.get('/', (req,res) => { + req.log.trace('trace message') + req.log.debug('debug message') + req.log.info('info message') + req.log.warn('warn message') + req.log.error('error message') + req.log.fatal('fatal message') + res.send('done') +}) + api_default.get('/test', (req,res) => { res.send('done') }) @@ -208,7 +219,7 @@ describe('Logging Tests:', function() { it('Default options (logging: true)', async function() { console.log = logger - let _event = Object.assign({},event,{ path: '/', queryStringParameters: { test: true } }) + let _event = Object.assign({},event,{ path: '/', multiValueQueryStringParameters: { test: ['val1'] } }) let result = await new Promise(r => api_default.run(_event,context,(e,res) => { r(res) })) console.log = consoleLog @@ -238,10 +249,47 @@ describe('Logging Tests:', function() { expect(_log[4]).to.have.property('ua') expect(_log[4]).to.have.property('version') expect(_log[4]).to.have.property('qs') + expect(_log[4].qs.test).to.be.a('string') expect(_log[4]).to.have.property('device') expect(_log[4]).to.have.property('country') }) // end it + it('Multi-value support', async function() { + console.log = logger + let _event = Object.assign({},event,{ path: '/', multiValueQueryStringParameters: { test: ['val1'] } }) + let result = await new Promise(r => api_multi.run(_event,context,(e,res) => { r(res) })) + console.log = consoleLog + + expect(result).to.deep.equal({ + multiValueHeaders: { 'content-type': ['application/json'] }, + statusCode: 200, + body: 'done', + isBase64Encoded: false + }) + expect(_log).to.have.length(5) + expect(_log[0].level).to.equal('info') + expect(_log[4].level).to.equal('access') + // standard log + expect(_log[0]).to.have.property('time') + expect(_log[0]).to.have.property('id') + expect(_log[0]).to.have.property('route') + expect(_log[0]).to.have.property('msg') + expect(_log[0]).to.have.property('timer') + expect(_log[0]).to.have.property('remaining') + expect(_log[0]).to.have.property('function') + expect(_log[0]).to.have.property('memory') + // access log + expect(_log[4]).to.have.property('coldStart') + expect(_log[4]).to.have.property('statusCode') + expect(_log[4]).to.have.property('path') + expect(_log[4]).to.have.property('ip') + expect(_log[4]).to.have.property('ua') + expect(_log[4]).to.have.property('version') + expect(_log[4]).to.have.property('qs') + expect(_log[4].qs.test).to.be.a('array') + expect(_log[4]).to.have.property('device') + expect(_log[4]).to.have.property('country') + }) // end it it('Default options (no logs in routes)', async function() { console.log = logger