Skip to content

Commit

Permalink
feat: change formatter to output valid json (#40)
Browse files Browse the repository at this point in the history
* feat: add config to control context inspection depth

* chore: stringify
  • Loading branch information
kleyow authored Nov 21, 2022
1 parent f39c123 commit c2a761e
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 24 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Edit the file in `./config/default.json` to configure the logger, or set the fol
| `CSL_LOG_FILTER` | Applies a log filter. Specify a comma separated list of individual log levels to be included instead of specifying a `LOG_LEVEL` | `""` | e.g. `"error, trace, verbose" |
| `CSL_LOG_TRANSPORT` | Selects the transport method. Either `console` or `file`. Uses the same transport for errors and standard logs | `console` | `console`, `file`
| `CSL_TRANSPORT_FILE_OPTIONS` | _Optional._ Required if `LOG_TRANSPORT=file`. Configures the winston file transport | See `default.json` | See the [Winston Docs](https://github.com/winstonjs/winston#common-transport-options) |

| `CSL_JSON_STRINGIFY_SPACING` | _Optional._ A number that's used to insert white space into the output JSON string for readability purposes. | 2 | integer



Expand Down
5 changes: 3 additions & 2 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"prettyPrint": true,
"colorize": true,
"filename": "logs/combined.log"
}
}
},
"JSON_STRINGIFY_SPACING": 2
}
25 changes: 13 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@types/node": "^18.11.9",
"parse-strings-in-object": "2.0.0",
"rc": "1.2.8",
"safe-stable-stringify": "^2.4.1",
"winston": "3.8.2"
},
"devDependencies": {
Expand Down
13 changes: 7 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,27 @@

'use strict'

const util = require('util')
const { createLogger, format, transports } = require('winston')
const { combine, timestamp, colorize, printf } = format
const stringify = require('safe-stable-stringify')

const { customLevels, level, logTransport, transportFileOptions } = require('./lib/config')
const { customLevels, level, logTransport, transportFileOptions, jsonStringifySpacing } = require('./lib/config')

const allLevels = { error: 0, warn: 1, audit: 2, trace: 3, info: 4, perf: 5, verbose: 6, debug: 7, silly: 8 }
const customLevelsArr = customLevels.split(/ *, */) // extra white space before/after the comma is ignored
const ignoredLevels = customLevels ? Object.keys(allLevels).filter(key => !customLevelsArr.includes(key)) : []

const customFormat = printf(({ level, message, timestamp, context }) => {
let formattedMessage = message
if (context && context instanceof Object) {
message = util.inspect({
formattedMessage = {
...context,
message
})
}
}
return `${timestamp} - ${level}: ${message}`
formattedMessage = stringify(formattedMessage, null, jsonStringifySpacing)
return `${timestamp} - ${level}: ${formattedMessage}`
})

let transport = new transports.Console()
if (logTransport === 'file') {
transport = new transports.File(transportFileOptions)
Expand Down
1 change: 1 addition & 0 deletions src/lib/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export const customLevels: any;
export const level: any;
export const logTransport: any;
export const transportFileOptions: any;
export const jsonStringifySpacing: any;
3 changes: 2 additions & 1 deletion src/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const Config = {
customLevels: process.env.LOG_FILTER || RC.LOG_FILTER,
level: process.env.LOG_LEVEL || RC.LOG_LEVEL,
logTransport: RC.LOG_TRANSPORT,
transportFileOptions: RC.TRANSPORT_FILE_OPTIONS
transportFileOptions: RC.TRANSPORT_FILE_OPTIONS,
jsonStringifySpacing: RC.JSON_STRINGIFY_SPACING
}

module.exports = Config
25 changes: 23 additions & 2 deletions test/unit/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Winston = require('winston')
const Proxyquire = require('proxyquire')
const Logger = require('../../src/index')
const config = require('../../src/lib/config')
const stringify = require('safe-stable-stringify')

Test('logger', function (loggerTest) {
let sandbox
Expand Down Expand Up @@ -103,14 +104,34 @@ Test('contextual logger', function (loggerTest) {
loggerTest.test('logger with context formats message properly', function (assert) {
const logger = Logger.child({ context: { a: 1 } })
logger.info('Message')
assert.ok(process.stdout.write.firstCall.args[0].split('info\x1B[39m: ')[1] === '{ a: 1, message: \'Message\' }\n')
assert.ok(process.stdout.write.firstCall.args[0].split('info\x1B[39m: ')[1] === stringify(
{ a: 1, message: 'Message' },
null,
config.jsonStringifySpacing) + '\n')
assert.end()
})

loggerTest.test('handles circular references gracefully', function (assert) {
const obj1 = {
a: 1
}
const obj2 = {
obj1
}
obj1.newobj2 = obj2
const logger = Logger.child({ context: { a: obj2 } })
logger.info('Message')
assert.ok(process.stdout.write.firstCall.args[0].split('info\x1B[39m: ')[1] === stringify(
{ a: obj2, message: 'Message' },
null,
config.jsonStringifySpacing) + '\n')
assert.end()
})

loggerTest.test('logger without context formats message properly', function (assert) {
const logger = Logger.child()
logger.info('Message')
assert.ok(process.stdout.write.firstCall.args[0].split('info\x1B[39m: ')[1] === 'Message\n')
assert.ok(process.stdout.write.firstCall.args[0].split('info\x1B[39m: ')[1] === '"Message"\n')
assert.end()
})

Expand Down

0 comments on commit c2a761e

Please sign in to comment.