Skip to content

Commit

Permalink
fix: DEBUG_SPACES for json serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
commenthol committed Oct 15, 2023
1 parent 35e69f1 commit d76c630
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 122 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "debug-level",
"version": "3.1.1",
"version": "3.1.2-0",
"description": "debug with levels",
"keywords": [
"debug",
Expand Down
14 changes: 9 additions & 5 deletions src/Format.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { format as quickFormat } from './quick-format.js'

export class Format {
/**
* @param {FormatOption} opts
* @param {FormatOption} [opts]
*/
constructor (opts = {}) {
this.opts = { opts }
constructor (opts) {
const { spaces } = opts || {}
this.opts = { spaces }
this._formatOpts()
}

Expand All @@ -25,8 +26,11 @@ export class Format {
}

_formatOpts () {
// @ts-expect-error
this.formatOpts = { stringify: (o) => fastStringify(o, null, this.opts.spaces) }
this.formatOpts = {
// @ts-expect-error
stringify: (o) => fastStringify(o, null, this.opts.spaces),
spaces: this.opts.spaces
}
}

stringify (...args) {
Expand Down
25 changes: 5 additions & 20 deletions src/ecs/LogEcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class LogEcs extends Log {

/* c8 ignore next 18 */
_applySerializers (obj) {
const name = this.name
const ecsObj = {}
for (const key in obj) {
const value = obj[key]
Expand All @@ -37,8 +38,9 @@ export class LogEcs extends Log {
if (this.serializers && this.serializers[key]) {
this.serializers[key](value, ecsObj)
} else {
ecsObj.extra = ecsObj.extra || {}
ecsObj.extra[key] = value
// add all other unknown fields to extra
ecsObj.extra = ecsObj.extra || { [name]: {} }
ecsObj.extra[name][key] = value
}
}
}
Expand Down Expand Up @@ -76,26 +78,9 @@ function toJson (obj, serializers) {
} else {
// add all other unknown fields to extra
ecsObj.extra = ecsObj.extra || { [name]: {} }
ecsObj.extra[name][key] = normToString(value)
ecsObj.extra[name][key] = value
}
}

return stringify(ecsObj)
}

/**
* elastic is picky on indexing types; for this all entries in e.g. extra are
* set to string to avoid any type collisions
* @param {any} val
* @returns {string}
*/
const normToString = (val) => {
switch (typeof val) {
case 'string':
return val
case 'number':
return String(val)
default:
return stringify(val)
}
}
5 changes: 4 additions & 1 deletion src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { wrapConsole } from './wrapConsole.js'
import { wrapDebug } from './wrapDebug.js'
import { Sonic } from './Sonic.js'
import { errSerializer } from './serializers/err.js'
import { Format } from './Format.js'

const env = process.env.NODE_ENV || 'development'
const isDevEnv = /^dev/.test(env) // anything which starts with dev is seen as development env
Expand Down Expand Up @@ -81,6 +82,8 @@ export class Log extends LogBase {
: this.opts.stream || process.stderr

if (!this.opts.json) {
this.opts.spaces = this.opts.spaces ?? 2
this.formatter = new Format(this.opts)
this._log = this._logDebugLike
} else if (this.opts.colors) {
this._log = this._logJsonColor
Expand Down Expand Up @@ -231,7 +234,7 @@ export class Log extends LogBase {
this._color(this.name, this.color, true)

const strOther = Object.keys(other).length
? stringify(this._applySerializers(other), this.opts.splitLine ? 2 : undefined)
? stringify(this._applySerializers(other), this.opts.splitLine ? (this.opts.spaces ?? 2) : undefined)
: ''

const str = (this.opts.splitLine)
Expand Down
9 changes: 5 additions & 4 deletions src/quick-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
* @copyright Copyright (c) 2016-2019 David Mark Clements
*/

function tryStringify (o) {
try { return JSON.stringify(o) } catch (e) { return '"[Circular]"' }
function tryStringify (value, replacer, spaces) {
try { return JSON.stringify(value, replacer, spaces) } catch (e) { return '"[Circular]"' }
}

export function format (f, args, opts, obj = {}) {
const ss = (opts && opts.stringify) || tryStringify
const stringify = opts?.stringify || tryStringify
const spaces = opts?.spaces
const argLen = args.length
let a = 0
let str = ''
Expand Down Expand Up @@ -78,7 +79,7 @@ export function format (f, args, opts, obj = {}) {
i++
break
}
str += ss(args[a])
str += stringify(args[a], null, spaces)
lastPos = i + 2
i++
break
Expand Down
174 changes: 102 additions & 72 deletions test/LogEcs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,89 +226,119 @@ describe('LogEcs', function () {
})
})

describe('json', function () {
const f = fixtures.json
let log
let clock
const exp = []
describe('formats', function () {
describe('debug like', function () {
const f = fixtures.debug
let log
let clock
const exp = []

before(() => {
clock = sinon.useFakeTimers()
LogEcs.options({ level: 'error', json: false, colors: false, namespaces: 'test*' })
log = new LogEcs('test', { timestamp: 'iso' })
})

before(() => {
clock = sinon.useFakeTimers()
LogEcs.options({
level: 'error',
namespaces: 'test*',
json: true,
colors: false,
serverinfo: false
after(() => {
clock.restore()
if (WRITE) console.log(inspect(exp))
LogEcs.reset()
})
log = new LogEcs('test', { timestamp: 'epoch' })
})

after(() => {
clock.restore()
if (WRITE) console.log(inspect(exp))
testcases.forEach(({ name, args }, idx) => {
it(name, function () {
const res = log.error(...args)
clock.tick(1)
if (WRITE) exp.push(res)
else assert.strictEqual(res, f[idx], res + ' !== ' + f[idx])
})
})
})

it('should NOT remove object only formatters', function () {
const log = new LogEcs('*')
const res = log.error('%j ', { a: { b: 'c' } })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"*","diff_ms":0},"message":"{\\"a\\":{\\"b\\":\\"c\\"}} ","@timestamp":"1970-01-01T00:00:00.000Z"}'
)
})
describe('json', function () {
const f = fixtures.json
let log
let clock
const exp = []

before(() => {
clock = sinon.useFakeTimers()
LogEcs.options({
level: 'error',
namespaces: 'test*',
json: true,
colors: false,
serverinfo: false
})
log = new LogEcs('test', { timestamp: 'epoch' })
})

it('should log serverinfo and pid', function () {
const log = new LogEcs('*', {
level: undefined,
serverinfo: true,
json: true
after(() => {
clock.restore()
if (WRITE) console.log(inspect(exp))
})
const res = log.error('test')
assert(
res.indexOf('"hostname":"' + os.hostname()) !== -1,
'missing hostname'
)
assert(res.indexOf('"pid":' + process.pid) !== -1, 'missing pid')
})

it('should not overwrite level', function () {
const err = new Error('Baam')
err.level = 'TEST_LEVEL'
err.name = 'TEST_NAME'
err.stack = err.stack.substring(0, 20)
const log = new LogEcs('all')
const res = log.log(err)
assert.strictEqual(
res,
'{"log":{"level":"LOG","logger":"all","diff_ms":0},"message":"Baam","@timestamp":"1970-01-01T00:00:00.000Z","error":{"type":"Error","message":"Baam","stack_trace":"TEST_NAME: Baam\\n "}}'
)
})
it('should NOT remove object only formatters', function () {
const log = new LogEcs('*')
const res = log.error('%j ', { a: { b: 'c' } })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"*","diff_ms":0},"message":"{\\"a\\":{\\"b\\":\\"c\\"}} ","@timestamp":"1970-01-01T00:00:00.000Z"}'
)
})

it('should stringify large string', function () {
const largeString = new Array(150).fill('1').join('')
const res = log.error({ largeString })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"test","diff_ms":0},"@timestamp":"1970-01-01T00:00:00.000Z","extra":{"test":{"largeString":"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}}}'
)
})
it('should log serverinfo and pid', function () {
const log = new LogEcs('*', {
level: undefined,
serverinfo: true,
json: true
})
const res = log.error('test')
assert(
res.indexOf('"hostname":"' + os.hostname()) !== -1,
'missing hostname'
)
assert(res.indexOf('"pid":' + process.pid) !== -1, 'missing pid')
})

it('should remove infinite number and function', function () {
const res = log.error({ number: Infinity, fn: () => {} })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"test","diff_ms":0},"@timestamp":"1970-01-01T00:00:00.000Z","extra":{"test":{"number":"Infinity"}}}'
)
})
it('should not overwrite level', function () {
const err = new Error('Baam')
err.level = 'TEST_LEVEL'
err.name = 'TEST_NAME'
err.stack = err.stack.substring(0, 20)
const log = new LogEcs('all')
const res = log.log(err)
assert.strictEqual(
res,
'{"log":{"level":"LOG","logger":"all","diff_ms":0},"message":"Baam","@timestamp":"1970-01-01T00:00:00.000Z","error":{"type":"Error","message":"Baam","stack_trace":"TEST_NAME: Baam\\n "}}'
)
})

it('should stringify large string', function () {
const largeString = new Array(150).fill('1').join('')
const res = log.error({ largeString })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"test","diff_ms":0},"@timestamp":"1970-01-01T00:00:00.000Z","extra":{"test":{"largeString":"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}}}'
)
})

testcases.forEach(({ name, args }, idx) => {
it(name, function () {
const res = log.error(...args)
clock.tick(1)
// console.log('%s', JSON.stringify(res))
if (WRITE) exp.push(res)
else assert.strictEqual(res, f[idx], res + ' !== ' + f[idx])
it('should log infinite number as null and remove function', function () {
const res = log.error({ number: Infinity, fn: () => {} })
assert.strictEqual(
res,
'{"log":{"level":"ERROR","logger":"test","diff_ms":0},"@timestamp":"1970-01-01T00:00:00.000Z","extra":{"test":{"number":null}}}'
)
})

testcases.forEach(({ name, args }, idx) => {
it(name, function () {
const res = log.error(...args)
clock.tick(1)
// console.log('%s', JSON.stringify(res))
if (WRITE) exp.push(res)
else assert.strictEqual(res, f[idx], res + ' !== ' + f[idx])
})
})
})
})
Expand Down
Loading

0 comments on commit d76c630

Please sign in to comment.