Projektstart
This commit is contained in:
71
backend/node_modules/pino-pretty/lib/utils/build-safe-sonic-boom.js
generated
vendored
Normal file
71
backend/node_modules/pino-pretty/lib/utils/build-safe-sonic-boom.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = buildSafeSonicBoom
|
||||
|
||||
const { isMainThread } = require('worker_threads')
|
||||
const SonicBoom = require('sonic-boom')
|
||||
const noop = require('./noop')
|
||||
|
||||
/**
|
||||
* Creates a safe SonicBoom instance
|
||||
*
|
||||
* @param {object} opts Options for SonicBoom
|
||||
*
|
||||
* @returns {object} A new SonicBoom stream
|
||||
*/
|
||||
function buildSafeSonicBoom (opts) {
|
||||
const stream = new SonicBoom(opts)
|
||||
stream.on('error', filterBrokenPipe)
|
||||
// if we are sync: false, we must flush on exit
|
||||
// NODE_V8_COVERAGE must breaks everything
|
||||
// https://github.com/nodejs/node/issues/49344
|
||||
if (!process.env.NODE_V8_COVERAGE && !opts.sync && isMainThread) {
|
||||
setupOnExit(stream)
|
||||
}
|
||||
return stream
|
||||
|
||||
function filterBrokenPipe (err) {
|
||||
if (err.code === 'EPIPE') {
|
||||
stream.write = noop
|
||||
stream.end = noop
|
||||
stream.flushSync = noop
|
||||
stream.destroy = noop
|
||||
return
|
||||
}
|
||||
stream.removeListener('error', filterBrokenPipe)
|
||||
}
|
||||
}
|
||||
|
||||
function setupOnExit (stream) {
|
||||
/* istanbul ignore next */
|
||||
if (global.WeakRef && global.WeakMap && global.FinalizationRegistry) {
|
||||
// This is leak free, it does not leave event handlers
|
||||
const onExit = require('on-exit-leak-free')
|
||||
|
||||
onExit.register(stream, autoEnd)
|
||||
|
||||
stream.on('close', function () {
|
||||
onExit.unregister(stream)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function autoEnd (stream, eventName) {
|
||||
// This check is needed only on some platforms
|
||||
|
||||
if (stream.destroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
if (eventName === 'beforeExit') {
|
||||
// We still have an event loop, let's use it
|
||||
stream.flush()
|
||||
stream.on('drain', function () {
|
||||
stream.end()
|
||||
})
|
||||
} else {
|
||||
// We do not have an event loop, so flush synchronously
|
||||
stream.flushSync()
|
||||
}
|
||||
}
|
||||
86
backend/node_modules/pino-pretty/lib/utils/build-safe-sonic-boom.test.js
generated
vendored
Normal file
86
backend/node_modules/pino-pretty/lib/utils/build-safe-sonic-boom.test.js
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const rimraf = require('rimraf')
|
||||
const fs = require('fs')
|
||||
const { join } = require('path')
|
||||
|
||||
const buildSafeSonicBoom = require('./build-safe-sonic-boom')
|
||||
|
||||
function noop () {}
|
||||
|
||||
const file = () => {
|
||||
const dest = join(__dirname, `${process.pid}-${process.hrtime().toString()}`)
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
return { dest, fd }
|
||||
}
|
||||
|
||||
tap.test('should not write when error emitted and code is "EPIPE"', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const { fd, dest } = file()
|
||||
const stream = buildSafeSonicBoom({ sync: true, fd, mkdir: true })
|
||||
t.teardown(() => rimraf(dest, noop))
|
||||
|
||||
stream.emit('error', { code: 'EPIPE' })
|
||||
stream.write('will not work')
|
||||
|
||||
const dataFile = fs.readFileSync(dest)
|
||||
t.equal(dataFile.length, 0)
|
||||
})
|
||||
|
||||
tap.test('should stream.write works when error code is not "EPIPE"', async t => {
|
||||
t.plan(3)
|
||||
const { fd, dest } = file()
|
||||
const stream = buildSafeSonicBoom({ sync: true, fd, mkdir: true })
|
||||
|
||||
t.teardown(() => rimraf(dest, noop))
|
||||
|
||||
stream.on('error', () => t.pass('error emitted'))
|
||||
|
||||
stream.emit('error', 'fake error description')
|
||||
|
||||
t.ok(stream.write('will work'))
|
||||
|
||||
const dataFile = fs.readFileSync(dest)
|
||||
t.equal(dataFile.toString(), 'will work')
|
||||
})
|
||||
|
||||
tap.test('cover setupOnExit', async t => {
|
||||
t.plan(3)
|
||||
const { fd, dest } = file()
|
||||
const stream = buildSafeSonicBoom({ sync: false, fd, mkdir: true })
|
||||
|
||||
t.teardown(() => rimraf(dest, noop))
|
||||
|
||||
stream.on('error', () => t.pass('error emitted'))
|
||||
stream.emit('error', 'fake error description')
|
||||
|
||||
t.ok(stream.write('will work'))
|
||||
|
||||
await watchFileCreated(dest)
|
||||
|
||||
const dataFile = fs.readFileSync(dest)
|
||||
t.equal(dataFile.toString(), 'will work')
|
||||
})
|
||||
|
||||
function watchFileCreated (filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const TIMEOUT = 2000
|
||||
const INTERVAL = 100
|
||||
const threshold = TIMEOUT / INTERVAL
|
||||
let counter = 0
|
||||
const interval = setInterval(() => {
|
||||
// On some CI runs file is created but not filled
|
||||
if (fs.existsSync(filename) && fs.statSync(filename).size !== 0) {
|
||||
clearInterval(interval)
|
||||
resolve()
|
||||
} else if (counter <= threshold) {
|
||||
counter++
|
||||
} else {
|
||||
clearInterval(interval)
|
||||
reject(new Error(`${filename} was not created.`))
|
||||
}
|
||||
}, INTERVAL)
|
||||
})
|
||||
}
|
||||
26
backend/node_modules/pino-pretty/lib/utils/create-date.js
generated
vendored
Normal file
26
backend/node_modules/pino-pretty/lib/utils/create-date.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = createDate
|
||||
|
||||
const isValidDate = require('./is-valid-date')
|
||||
|
||||
/**
|
||||
* Constructs a JS Date from a number or string. Accepts any single number
|
||||
* or single string argument that is valid for the Date() constructor,
|
||||
* or an epoch as a string.
|
||||
*
|
||||
* @param {string|number} epoch The representation of the Date.
|
||||
*
|
||||
* @returns {Date} The constructed Date.
|
||||
*/
|
||||
function createDate (epoch) {
|
||||
// If epoch is already a valid argument, return the valid Date
|
||||
let date = new Date(epoch)
|
||||
if (isValidDate(date)) {
|
||||
return date
|
||||
}
|
||||
|
||||
// Convert to a number to permit epoch as a string
|
||||
date = new Date(+epoch)
|
||||
return date
|
||||
}
|
||||
20
backend/node_modules/pino-pretty/lib/utils/create-date.test.js
generated
vendored
Normal file
20
backend/node_modules/pino-pretty/lib/utils/create-date.test.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const createDate = require('./create-date')
|
||||
|
||||
const wanted = 1624450038567
|
||||
|
||||
tap.test('accepts arguments the Date constructor would accept', async t => {
|
||||
t.plan(2)
|
||||
t.same(createDate(1624450038567).getTime(), wanted)
|
||||
t.same(createDate('2021-06-23T12:07:18.567Z').getTime(), wanted)
|
||||
})
|
||||
|
||||
tap.test('accepts epoch as a string', async t => {
|
||||
// If Date() accepts this argument, the createDate function is not needed
|
||||
// and can be replaced with Date()
|
||||
t.plan(2)
|
||||
t.notSame(new Date('16244500385-67').getTime(), wanted)
|
||||
t.same(createDate('1624450038567').getTime(), wanted)
|
||||
})
|
||||
28
backend/node_modules/pino-pretty/lib/utils/delete-log-property.js
generated
vendored
Normal file
28
backend/node_modules/pino-pretty/lib/utils/delete-log-property.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = deleteLogProperty
|
||||
|
||||
const getPropertyValue = require('./get-property-value')
|
||||
const splitPropertyKey = require('./split-property-key')
|
||||
|
||||
/**
|
||||
* Deletes a specified property from a log object if it exists.
|
||||
* This function mutates the passed in `log` object.
|
||||
*
|
||||
* @param {object} log The log object to be modified.
|
||||
* @param {string} property A string identifying the property to be deleted from
|
||||
* the log object. Accepts nested properties delimited by a `.`
|
||||
* Delimiter can be escaped to preserve property names that contain the delimiter.
|
||||
* e.g. `'prop1.prop2'` or `'prop2\.domain\.corp.prop2'`
|
||||
*/
|
||||
function deleteLogProperty (log, property) {
|
||||
const props = splitPropertyKey(property)
|
||||
const propToDelete = props.pop()
|
||||
|
||||
log = getPropertyValue(log, props)
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (log !== null && typeof log === 'object' && Object.prototype.hasOwnProperty.call(log, propToDelete)) {
|
||||
delete log[propToDelete]
|
||||
}
|
||||
}
|
||||
31
backend/node_modules/pino-pretty/lib/utils/delete-log-property.test.js
generated
vendored
Normal file
31
backend/node_modules/pino-pretty/lib/utils/delete-log-property.test.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { createCopier } = require('fast-copy')
|
||||
const fastCopy = createCopier({})
|
||||
const deleteLogProperty = require('./delete-log-property')
|
||||
|
||||
const logData = {
|
||||
level: 30,
|
||||
data1: {
|
||||
data2: { 'data-3': 'bar' }
|
||||
}
|
||||
}
|
||||
|
||||
tap.test('deleteLogProperty deletes property of depth 1', async t => {
|
||||
const log = fastCopy(logData)
|
||||
deleteLogProperty(log, 'data1')
|
||||
t.same(log, { level: 30 })
|
||||
})
|
||||
|
||||
tap.test('deleteLogProperty deletes property of depth 2', async t => {
|
||||
const log = fastCopy(logData)
|
||||
deleteLogProperty(log, 'data1.data2')
|
||||
t.same(log, { level: 30, data1: { } })
|
||||
})
|
||||
|
||||
tap.test('deleteLogProperty deletes property of depth 3', async t => {
|
||||
const log = fastCopy(logData)
|
||||
deleteLogProperty(log, 'data1.data2.data-3')
|
||||
t.same(log, { level: 30, data1: { data2: { } } })
|
||||
})
|
||||
45
backend/node_modules/pino-pretty/lib/utils/filter-log.js
generated
vendored
Normal file
45
backend/node_modules/pino-pretty/lib/utils/filter-log.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = filterLog
|
||||
|
||||
const { createCopier } = require('fast-copy')
|
||||
const fastCopy = createCopier({})
|
||||
|
||||
const deleteLogProperty = require('./delete-log-property')
|
||||
|
||||
/**
|
||||
* @typedef {object} FilterLogParams
|
||||
* @property {object} log The log object to be modified.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Filter a log object by removing or including keys accordingly.
|
||||
* When `includeKeys` is passed, `ignoredKeys` will be ignored.
|
||||
* One of ignoreKeys or includeKeys must be pass in.
|
||||
*
|
||||
* @param {FilterLogParams} input
|
||||
*
|
||||
* @returns {object} A new `log` object instance that
|
||||
* either only includes the keys in ignoreKeys
|
||||
* or does not include those in ignoredKeys.
|
||||
*/
|
||||
function filterLog ({ log, context }) {
|
||||
const { ignoreKeys, includeKeys } = context
|
||||
const logCopy = fastCopy(log)
|
||||
|
||||
if (includeKeys) {
|
||||
const logIncluded = {}
|
||||
|
||||
includeKeys.forEach((key) => {
|
||||
logIncluded[key] = logCopy[key]
|
||||
})
|
||||
return logIncluded
|
||||
}
|
||||
|
||||
ignoreKeys.forEach((ignoreKey) => {
|
||||
deleteLogProperty(logCopy, ignoreKey)
|
||||
})
|
||||
return logCopy
|
||||
}
|
||||
190
backend/node_modules/pino-pretty/lib/utils/filter-log.test.js
generated
vendored
Normal file
190
backend/node_modules/pino-pretty/lib/utils/filter-log.test.js
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const filterLog = require('./filter-log')
|
||||
|
||||
const context = {
|
||||
includeKeys: undefined,
|
||||
ignoreKeys: undefined
|
||||
}
|
||||
const logData = {
|
||||
level: 30,
|
||||
time: 1522431328992,
|
||||
data1: {
|
||||
data2: { 'data-3': 'bar' },
|
||||
error: new Error('test')
|
||||
}
|
||||
}
|
||||
const logData2 = Object.assign({
|
||||
'logging.domain.corp/operation': {
|
||||
id: 'foo',
|
||||
producer: 'bar'
|
||||
}
|
||||
}, logData)
|
||||
|
||||
tap.test('#filterLog with an ignoreKeys option', t => {
|
||||
t.test('filterLog removes single entry', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: ['data1.data2.data-3']
|
||||
}
|
||||
})
|
||||
t.same(result, { level: 30, time: 1522431328992, data1: { data2: { }, error: new Error('test') } })
|
||||
})
|
||||
|
||||
t.test('filterLog removes multiple entries', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: ['time', 'data1']
|
||||
}
|
||||
})
|
||||
t.same(result, { level: 30 })
|
||||
})
|
||||
|
||||
t.test('filterLog keeps error instance', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: []
|
||||
}
|
||||
})
|
||||
t.equal(logData.data1.error, result.data1.error)
|
||||
})
|
||||
|
||||
t.test('filterLog removes entry with escape sequence', async t => {
|
||||
const result = filterLog({
|
||||
log: logData2,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: ['data1', 'logging\\.domain\\.corp/operation']
|
||||
}
|
||||
})
|
||||
t.same(result, { level: 30, time: 1522431328992 })
|
||||
})
|
||||
|
||||
t.test('filterLog removes entry with escape sequence nested', async t => {
|
||||
const result = filterLog({
|
||||
log: logData2,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: ['data1', 'logging\\.domain\\.corp/operation.producer']
|
||||
}
|
||||
})
|
||||
t.same(result, { level: 30, time: 1522431328992, 'logging.domain.corp/operation': { id: 'foo' } })
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
const ignoreKeysArray = [
|
||||
undefined,
|
||||
['level'],
|
||||
['level', 'data1.data2.data-3']
|
||||
]
|
||||
ignoreKeysArray.forEach(ignoreKeys => {
|
||||
tap.test(`#filterLog with an includeKeys option when the ignoreKeys being ${ignoreKeys}`, t => {
|
||||
t.test('filterLog include nothing', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys,
|
||||
includeKeys: []
|
||||
}
|
||||
})
|
||||
t.same(result, {})
|
||||
})
|
||||
|
||||
t.test('filterLog include single entry', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys,
|
||||
includeKeys: ['time']
|
||||
}
|
||||
})
|
||||
t.same(result, { time: 1522431328992 })
|
||||
})
|
||||
|
||||
t.test('filterLog include multiple entries', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys,
|
||||
includeKeys: ['time', 'data1']
|
||||
}
|
||||
})
|
||||
t.same(result, {
|
||||
time: 1522431328992,
|
||||
data1: {
|
||||
data2: { 'data-3': 'bar' },
|
||||
error: new Error('test')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
tap.test('#filterLog with circular references', t => {
|
||||
const logData = {
|
||||
level: 30,
|
||||
time: 1522431328992,
|
||||
data1: 'test'
|
||||
}
|
||||
logData.circular = logData
|
||||
|
||||
t.test('filterLog removes single entry', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
ignoreKeys: ['data1']
|
||||
}
|
||||
})
|
||||
|
||||
t.same(result.circular.level, result.level)
|
||||
t.same(result.circular.time, result.time)
|
||||
|
||||
delete result.circular
|
||||
t.same(result, { level: 30, time: 1522431328992 })
|
||||
})
|
||||
|
||||
t.test('filterLog includes single entry', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
includeKeys: ['data1']
|
||||
}
|
||||
})
|
||||
|
||||
t.same(result, { data1: 'test' })
|
||||
})
|
||||
|
||||
t.test('filterLog includes circular keys', async t => {
|
||||
const result = filterLog({
|
||||
log: logData,
|
||||
context: {
|
||||
...context,
|
||||
includeKeys: ['level', 'circular']
|
||||
}
|
||||
})
|
||||
|
||||
t.same(result.circular.level, logData.level)
|
||||
t.same(result.circular.time, logData.time)
|
||||
|
||||
delete result.circular
|
||||
t.same(result, { level: 30 })
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
66
backend/node_modules/pino-pretty/lib/utils/format-time.js
generated
vendored
Normal file
66
backend/node_modules/pino-pretty/lib/utils/format-time.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = formatTime
|
||||
|
||||
const {
|
||||
DATE_FORMAT,
|
||||
DATE_FORMAT_SIMPLE
|
||||
} = require('../constants')
|
||||
|
||||
const dateformat = require('dateformat')
|
||||
const createDate = require('./create-date')
|
||||
const isValidDate = require('./is-valid-date')
|
||||
|
||||
/**
|
||||
* Converts a given `epoch` to a desired display format.
|
||||
*
|
||||
* @param {number|string} epoch The time to convert. May be any value that is
|
||||
* valid for `new Date()`.
|
||||
* @param {boolean|string} [translateTime=false] When `false`, the given `epoch`
|
||||
* will simply be returned. When `true`, the given `epoch` will be converted
|
||||
* to a string at UTC using the `DATE_FORMAT` constant. If `translateTime` is
|
||||
* a string, the following rules are available:
|
||||
*
|
||||
* - `<format string>`: The string is a literal format string. This format
|
||||
* string will be used to interpret the `epoch` and return a display string
|
||||
* at UTC.
|
||||
* - `SYS:STANDARD`: The returned display string will follow the `DATE_FORMAT`
|
||||
* constant at the system's local timezone.
|
||||
* - `SYS:<format string>`: The returned display string will follow the given
|
||||
* `<format string>` at the system's local timezone.
|
||||
* - `UTC:<format string>`: The returned display string will follow the given
|
||||
* `<format string>` at UTC.
|
||||
*
|
||||
* @returns {number|string} The formatted time.
|
||||
*/
|
||||
function formatTime (epoch, translateTime = false) {
|
||||
if (translateTime === false) {
|
||||
return epoch
|
||||
}
|
||||
|
||||
const instant = createDate(epoch)
|
||||
|
||||
// If the Date is invalid, do not attempt to format
|
||||
if (!isValidDate(instant)) {
|
||||
return epoch
|
||||
}
|
||||
|
||||
if (translateTime === true) {
|
||||
return dateformat(instant, DATE_FORMAT_SIMPLE)
|
||||
}
|
||||
|
||||
const upperFormat = translateTime.toUpperCase()
|
||||
if (upperFormat === 'SYS:STANDARD') {
|
||||
return dateformat(instant, DATE_FORMAT)
|
||||
}
|
||||
|
||||
const prefix = upperFormat.substr(0, 4)
|
||||
if (prefix === 'SYS:' || prefix === 'UTC:') {
|
||||
if (prefix === 'UTC:') {
|
||||
return dateformat(instant, translateTime)
|
||||
}
|
||||
return dateformat(instant, translateTime.slice(4))
|
||||
}
|
||||
|
||||
return dateformat(instant, `UTC:${translateTime}`)
|
||||
}
|
||||
71
backend/node_modules/pino-pretty/lib/utils/format-time.test.js
generated
vendored
Normal file
71
backend/node_modules/pino-pretty/lib/utils/format-time.test.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
const tap = require('tap')
|
||||
const formatTime = require('./format-time')
|
||||
|
||||
const dateStr = '2019-04-06T13:30:00.000-04:00'
|
||||
const epoch = new Date(dateStr)
|
||||
const epochMS = epoch.getTime()
|
||||
|
||||
tap.test('passes through epoch if `translateTime` is `false`', async t => {
|
||||
const formattedTime = formatTime(epochMS)
|
||||
t.equal(formattedTime, epochMS)
|
||||
})
|
||||
|
||||
tap.test('passes through epoch if date is invalid', async t => {
|
||||
const input = 'this is not a date'
|
||||
const formattedTime = formatTime(input, true)
|
||||
t.equal(formattedTime, input)
|
||||
})
|
||||
|
||||
tap.test('translates epoch milliseconds if `translateTime` is `true`', async t => {
|
||||
const formattedTime = formatTime(epochMS, true)
|
||||
t.equal(formattedTime, '17:30:00.000')
|
||||
})
|
||||
|
||||
tap.test('translates epoch milliseconds to UTC string given format', async t => {
|
||||
const formattedTime = formatTime(epochMS, 'd mmm yyyy H:MM')
|
||||
t.equal(formattedTime, '6 Apr 2019 17:30')
|
||||
})
|
||||
|
||||
tap.test('translates epoch milliseconds to SYS:STANDARD', async t => {
|
||||
const formattedTime = formatTime(epochMS, 'SYS:STANDARD')
|
||||
t.match(formattedTime, /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} [-+]?\d{4}/)
|
||||
})
|
||||
|
||||
tap.test('translates epoch milliseconds to SYS:<FORMAT>', async t => {
|
||||
const formattedTime = formatTime(epochMS, 'SYS:d mmm yyyy H:MM')
|
||||
t.match(formattedTime, /\d{1} \w{3} \d{4} \d{1,2}:\d{2}/)
|
||||
})
|
||||
|
||||
tap.test('passes through date string if `translateTime` is `false`', async t => {
|
||||
const formattedTime = formatTime(dateStr)
|
||||
t.equal(formattedTime, dateStr)
|
||||
})
|
||||
|
||||
tap.test('translates date string if `translateTime` is `true`', async t => {
|
||||
const formattedTime = formatTime(dateStr, true)
|
||||
t.equal(formattedTime, '17:30:00.000')
|
||||
})
|
||||
|
||||
tap.test('translates date string to UTC string given format', async t => {
|
||||
const formattedTime = formatTime(dateStr, 'd mmm yyyy H:MM')
|
||||
t.equal(formattedTime, '6 Apr 2019 17:30')
|
||||
})
|
||||
|
||||
tap.test('translates date string to SYS:STANDARD', async t => {
|
||||
const formattedTime = formatTime(dateStr, 'SYS:STANDARD')
|
||||
t.match(formattedTime, /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} [-+]?\d{4}/)
|
||||
})
|
||||
|
||||
tap.test('translates date string to UTC:<FORMAT>', async t => {
|
||||
const formattedTime = formatTime(dateStr, 'UTC:d mmm yyyy H:MM')
|
||||
t.equal(formattedTime, '6 Apr 2019 17:30')
|
||||
})
|
||||
|
||||
tap.test('translates date string to SYS:<FORMAT>', async t => {
|
||||
const formattedTime = formatTime(dateStr, 'SYS:d mmm yyyy H:MM')
|
||||
t.match(formattedTime, /\d{1} \w{3} \d{4} \d{1,2}:\d{2}/)
|
||||
})
|
||||
30
backend/node_modules/pino-pretty/lib/utils/get-property-value.js
generated
vendored
Normal file
30
backend/node_modules/pino-pretty/lib/utils/get-property-value.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = getPropertyValue
|
||||
|
||||
const splitPropertyKey = require('./split-property-key')
|
||||
|
||||
/**
|
||||
* Gets a specified property from an object if it exists.
|
||||
*
|
||||
* @param {object} obj The object to be searched.
|
||||
* @param {string|string[]} property A string, or an array of strings, identifying
|
||||
* the property to be retrieved from the object.
|
||||
* Accepts nested properties delimited by a `.`.
|
||||
* Delimiter can be escaped to preserve property names that contain the delimiter.
|
||||
* e.g. `'prop1.prop2'` or `'prop2\.domain\.corp.prop2'`.
|
||||
*
|
||||
* @returns {*}
|
||||
*/
|
||||
function getPropertyValue (obj, property) {
|
||||
const props = Array.isArray(property) ? property : splitPropertyKey(property)
|
||||
|
||||
for (const prop of props) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
|
||||
return
|
||||
}
|
||||
obj = obj[prop]
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
31
backend/node_modules/pino-pretty/lib/utils/get-property-value.test.js
generated
vendored
Normal file
31
backend/node_modules/pino-pretty/lib/utils/get-property-value.test.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const getPropertyValue = require('./get-property-value')
|
||||
|
||||
tap.test('getPropertyValue returns the value of the property', async t => {
|
||||
const result = getPropertyValue({
|
||||
foo: 'bar'
|
||||
}, 'foo')
|
||||
t.same(result, 'bar')
|
||||
})
|
||||
|
||||
tap.test('getPropertyValue returns the value of the nested property', async t => {
|
||||
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, 'extra.foo.value')
|
||||
t.same(result, 'bar')
|
||||
})
|
||||
|
||||
tap.test('getPropertyValue returns the value of the nested property using the array of nested property keys', async t => {
|
||||
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, ['extra', 'foo', 'value'])
|
||||
t.same(result, 'bar')
|
||||
})
|
||||
|
||||
tap.test('getPropertyValue returns undefined for non-existing properties', async t => {
|
||||
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, 'extra.foo.value-2')
|
||||
t.same(result, undefined)
|
||||
})
|
||||
|
||||
tap.test('getPropertyValue returns undefined for non-existing properties using the array of nested property keys', async t => {
|
||||
const result = getPropertyValue({ extra: { foo: { value: 'bar' } } }, ['extra', 'foo', 'value-2'])
|
||||
t.same(result, undefined)
|
||||
})
|
||||
38
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-names-opts.js
generated
vendored
Normal file
38
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-names-opts.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = handleCustomLevelsNamesOpts
|
||||
|
||||
/**
|
||||
* Parse a CSV string or options object that maps level
|
||||
* labels to level values.
|
||||
*
|
||||
* @param {string|object} cLevels An object mapping level
|
||||
* names to level values, e.g. `{ info: 30, debug: 65 }`, or a
|
||||
* CSV string in the format `level_name:level_value`, e.g.
|
||||
* `info:30,debug:65`.
|
||||
*
|
||||
* @returns {object} An object mapping levels names to level values
|
||||
* e.g. `{ info: 30, debug: 65 }`.
|
||||
*/
|
||||
function handleCustomLevelsNamesOpts (cLevels) {
|
||||
if (!cLevels) return {}
|
||||
|
||||
if (typeof cLevels === 'string') {
|
||||
return cLevels
|
||||
.split(',')
|
||||
.reduce((agg, value, idx) => {
|
||||
const [levelName, levelNum = idx] = value.split(':')
|
||||
agg[levelName.toLowerCase()] = levelNum
|
||||
return agg
|
||||
}, {})
|
||||
} else if (Object.prototype.toString.call(cLevels) === '[object Object]') {
|
||||
return Object
|
||||
.keys(cLevels)
|
||||
.reduce((agg, levelName) => {
|
||||
agg[levelName.toLowerCase()] = cLevels[levelName]
|
||||
return agg
|
||||
}, {})
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
44
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-names-opts.test.js
generated
vendored
Normal file
44
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-names-opts.test.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const handleCustomLevelsNamesOpts = require('./handle-custom-levels-names-opts')
|
||||
|
||||
tap.test('returns a empty object `{}` for undefined parameter', async t => {
|
||||
const handledCustomLevelNames = handleCustomLevelsNamesOpts()
|
||||
t.same(handledCustomLevelNames, {})
|
||||
})
|
||||
|
||||
tap.test('returns a empty object `{}` for unknown parameter', async t => {
|
||||
const handledCustomLevelNames = handleCustomLevelsNamesOpts(123)
|
||||
t.same(handledCustomLevelNames, {})
|
||||
})
|
||||
|
||||
tap.test('returns a filled object for string parameter', async t => {
|
||||
const handledCustomLevelNames = handleCustomLevelsNamesOpts('ok:10,warn:20,error:35')
|
||||
t.same(handledCustomLevelNames, {
|
||||
ok: 10,
|
||||
warn: 20,
|
||||
error: 35
|
||||
})
|
||||
})
|
||||
|
||||
tap.test('returns a filled object for object parameter', async t => {
|
||||
const handledCustomLevelNames = handleCustomLevelsNamesOpts({
|
||||
ok: 10,
|
||||
warn: 20,
|
||||
error: 35
|
||||
})
|
||||
t.same(handledCustomLevelNames, {
|
||||
ok: 10,
|
||||
warn: 20,
|
||||
error: 35
|
||||
})
|
||||
})
|
||||
|
||||
tap.test('defaults missing level num to first index', async t => {
|
||||
const result = handleCustomLevelsNamesOpts('ok:10,info')
|
||||
t.same(result, {
|
||||
ok: 10,
|
||||
info: 1
|
||||
})
|
||||
})
|
||||
39
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-opts.js
generated
vendored
Normal file
39
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-opts.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = handleCustomLevelsOpts
|
||||
|
||||
/**
|
||||
* Parse a CSV string or options object that specifies
|
||||
* configuration for custom levels.
|
||||
*
|
||||
* @param {string|object} cLevels An object mapping level
|
||||
* names to values, e.g. `{ info: 30, debug: 65 }`, or a
|
||||
* CSV string in the format `level_name:level_value`, e.g.
|
||||
* `info:30,debug:65`.
|
||||
*
|
||||
* @returns {object} An object mapping levels to labels that
|
||||
* appear in logs, e.g. `{ '30': 'INFO', '65': 'DEBUG' }`.
|
||||
*/
|
||||
function handleCustomLevelsOpts (cLevels) {
|
||||
if (!cLevels) return {}
|
||||
|
||||
if (typeof cLevels === 'string') {
|
||||
return cLevels
|
||||
.split(',')
|
||||
.reduce((agg, value, idx) => {
|
||||
const [levelName, levelNum = idx] = value.split(':')
|
||||
agg[levelNum] = levelName.toUpperCase()
|
||||
return agg
|
||||
},
|
||||
{ default: 'USERLVL' })
|
||||
} else if (Object.prototype.toString.call(cLevels) === '[object Object]') {
|
||||
return Object
|
||||
.keys(cLevels)
|
||||
.reduce((agg, levelName) => {
|
||||
agg[cLevels[levelName]] = levelName.toUpperCase()
|
||||
return agg
|
||||
}, { default: 'USERLVL' })
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
47
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-opts.test.js
generated
vendored
Normal file
47
backend/node_modules/pino-pretty/lib/utils/handle-custom-levels-opts.test.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const handleCustomLevelsOpts = require('./handle-custom-levels-opts')
|
||||
|
||||
tap.test('returns a empty object `{}` for undefined parameter', async t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts()
|
||||
t.same(handledCustomLevel, {})
|
||||
})
|
||||
|
||||
tap.test('returns a empty object `{}` for unknown parameter', async t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts(123)
|
||||
t.same(handledCustomLevel, {})
|
||||
})
|
||||
|
||||
tap.test('returns a filled object for string parameter', async t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts('ok:10,warn:20,error:35')
|
||||
t.same(handledCustomLevel, {
|
||||
10: 'OK',
|
||||
20: 'WARN',
|
||||
35: 'ERROR',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
|
||||
tap.test('returns a filled object for object parameter', async t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts({
|
||||
ok: 10,
|
||||
warn: 20,
|
||||
error: 35
|
||||
})
|
||||
t.same(handledCustomLevel, {
|
||||
10: 'OK',
|
||||
20: 'WARN',
|
||||
35: 'ERROR',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
|
||||
tap.test('defaults missing level num to first index', async t => {
|
||||
const result = handleCustomLevelsOpts('ok:10,info')
|
||||
t.same(result, {
|
||||
10: 'OK',
|
||||
1: 'INFO',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
99
backend/node_modules/pino-pretty/lib/utils/index.js
generated
vendored
Normal file
99
backend/node_modules/pino-pretty/lib/utils/index.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
buildSafeSonicBoom: require('./build-safe-sonic-boom.js'),
|
||||
createDate: require('./create-date.js'),
|
||||
deleteLogProperty: require('./delete-log-property.js'),
|
||||
filterLog: require('./filter-log.js'),
|
||||
formatTime: require('./format-time.js'),
|
||||
getPropertyValue: require('./get-property-value.js'),
|
||||
handleCustomLevelsNamesOpts: require('./handle-custom-levels-names-opts.js'),
|
||||
handleCustomLevelsOpts: require('./handle-custom-levels-opts.js'),
|
||||
interpretConditionals: require('./interpret-conditionals.js'),
|
||||
isObject: require('./is-object.js'),
|
||||
isValidDate: require('./is-valid-date.js'),
|
||||
joinLinesWithIndentation: require('./join-lines-with-indentation.js'),
|
||||
noop: require('./noop.js'),
|
||||
parseFactoryOptions: require('./parse-factory-options.js'),
|
||||
prettifyErrorLog: require('./prettify-error-log.js'),
|
||||
prettifyError: require('./prettify-error.js'),
|
||||
prettifyLevel: require('./prettify-level.js'),
|
||||
prettifyMessage: require('./prettify-message.js'),
|
||||
prettifyMetadata: require('./prettify-metadata.js'),
|
||||
prettifyObject: require('./prettify-object.js'),
|
||||
prettifyTime: require('./prettify-time.js'),
|
||||
splitPropertyKey: require('./split-property-key.js')
|
||||
}
|
||||
|
||||
// The remainder of this file consists of jsdoc blocks that are difficult to
|
||||
// determine a more appropriate "home" for. As an example, the blocks associated
|
||||
// with custom prettifiers could live in either the `prettify-level`,
|
||||
// `prettify-metadata`, or `prettify-time` files since they are the primary
|
||||
// files where such code is used. But we want a central place to define common
|
||||
// doc blocks, so we are picking this file as the answer.
|
||||
|
||||
/**
|
||||
* A hash of log property names mapped to prettifier functions. When the
|
||||
* incoming log data is being processed for prettification, any key on the log
|
||||
* that matches a key in a custom prettifiers hash will be prettified using
|
||||
* that matching custom prettifier. The value passed to the custom prettifier
|
||||
* will the value associated with the corresponding log key.
|
||||
*
|
||||
* The hash may contain any arbitrary keys for arbitrary log properties, but it
|
||||
* may also contain a set of predefined key names that map to well-known log
|
||||
* properties. These keys are:
|
||||
*
|
||||
* + `time` (for the timestamp field)
|
||||
* + `level` (for the level label field; value may be a level number instead
|
||||
* of a level label)
|
||||
* + `hostname`
|
||||
* + `pid`
|
||||
* + `name`
|
||||
* + `caller`
|
||||
*
|
||||
* @typedef {Object.<string, CustomPrettifierFunc>} CustomPrettifiers
|
||||
*/
|
||||
|
||||
/**
|
||||
* A synchronous function to be used for prettifying a log property. It must
|
||||
* return a string.
|
||||
*
|
||||
* @typedef {function} CustomPrettifierFunc
|
||||
* @param {any} value The value to be prettified for the key associated with
|
||||
* the prettifier.
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* A tokenized string that indicates how the prettified log line should be
|
||||
* formatted. Tokens are either log properties enclosed in curly braces, e.g.
|
||||
* `{levelLabel}`, `{pid}`, or `{req.url}`, or conditional directives in curly
|
||||
* braces. The only conditional directives supported are `if` and `end`, e.g.
|
||||
* `{if pid}{pid}{end}`; every `if` must have a matching `end`. Nested
|
||||
* conditions are not supported.
|
||||
*
|
||||
* @typedef {string} MessageFormatString
|
||||
*
|
||||
* @example
|
||||
* `{levelLabel} - {if pid}{pid} - {end}url:{req.url}`
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that accepts a log object, name of the message key, and name of
|
||||
* the level label key and returns a formatted log line.
|
||||
*
|
||||
* Note: this function must be synchronous.
|
||||
*
|
||||
* @typedef {function} MessageFormatFunction
|
||||
* @param {object} log The log object to be processed.
|
||||
* @param {string} messageKey The name of the key in the `log` object that
|
||||
* contains the log message.
|
||||
* @param {string} levelLabel The name of the key in the `log` object that
|
||||
* contains the log level name.
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* function (log, messageKey, levelLabel) {
|
||||
* return `${log[levelLabel]} - ${log[messageKey]}`
|
||||
* }
|
||||
*/
|
||||
37
backend/node_modules/pino-pretty/lib/utils/index.test.js
generated
vendored
Normal file
37
backend/node_modules/pino-pretty/lib/utils/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const index = require('./index.js')
|
||||
const { readdirSync } = require('fs')
|
||||
const { basename } = require('path')
|
||||
|
||||
tap.test(
|
||||
'index exports exactly all non-test files excluding itself',
|
||||
async t => {
|
||||
// Read all files in the `util` directory
|
||||
const files = readdirSync(__dirname)
|
||||
|
||||
for (const file of files) {
|
||||
const kebabName = basename(file, '.js')
|
||||
const snakeName = kebabName.split('-').map((part, idx) => {
|
||||
if (idx === 0) return part
|
||||
return part[0].toUpperCase() + part.slice(1)
|
||||
}).join('')
|
||||
|
||||
if (file.endsWith('.test.js') === false && file !== 'index.js') {
|
||||
// We expect all files to be exported except…
|
||||
t.ok(index[snakeName], `exports ${snakeName}`)
|
||||
} else {
|
||||
// …test files and the index file itself – those must not be exported
|
||||
t.notOk(index[snakeName], `does not export ${snakeName}`)
|
||||
}
|
||||
|
||||
// Remove the exported file from the index object
|
||||
delete index[snakeName]
|
||||
}
|
||||
|
||||
// Now the index is expected to be empty, as nothing else should be
|
||||
// exported from it
|
||||
t.same(index, {}, 'does not export anything else')
|
||||
}
|
||||
)
|
||||
37
backend/node_modules/pino-pretty/lib/utils/interpret-conditionals.js
generated
vendored
Normal file
37
backend/node_modules/pino-pretty/lib/utils/interpret-conditionals.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = interpretConditionals
|
||||
|
||||
const getPropertyValue = require('./get-property-value')
|
||||
|
||||
/**
|
||||
* Translates all conditional blocks from within the messageFormat. Translates
|
||||
* any matching {if key}{key}{end} statements and returns everything between
|
||||
* if and else blocks if the key provided was found in log.
|
||||
*
|
||||
* @param {MessageFormatString|MessageFormatFunction} messageFormat A format
|
||||
* string or function that defines how the logged message should be
|
||||
* conditionally formatted.
|
||||
* @param {object} log The log object to be modified.
|
||||
*
|
||||
* @returns {string} The parsed messageFormat.
|
||||
*/
|
||||
function interpretConditionals (messageFormat, log) {
|
||||
messageFormat = messageFormat.replace(/{if (.*?)}(.*?){end}/g, replacer)
|
||||
|
||||
// Remove non-terminated if blocks
|
||||
messageFormat = messageFormat.replace(/{if (.*?)}/g, '')
|
||||
// Remove floating end blocks
|
||||
messageFormat = messageFormat.replace(/{end}/g, '')
|
||||
|
||||
return messageFormat.replace(/\s+/g, ' ').trim()
|
||||
|
||||
function replacer (_, key, value) {
|
||||
const propertyValue = getPropertyValue(log, key)
|
||||
if (propertyValue && value.includes(key)) {
|
||||
return value.replace(new RegExp('{' + key + '}', 'g'), propertyValue)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
69
backend/node_modules/pino-pretty/lib/utils/interpret-conditionals.test.js
generated
vendored
Normal file
69
backend/node_modules/pino-pretty/lib/utils/interpret-conditionals.test.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const { createCopier } = require('fast-copy')
|
||||
const fastCopy = createCopier({})
|
||||
const interpretConditionals = require('./interpret-conditionals')
|
||||
|
||||
const logData = {
|
||||
level: 30,
|
||||
data1: {
|
||||
data2: 'bar'
|
||||
},
|
||||
msg: 'foo'
|
||||
}
|
||||
|
||||
tap.test('interpretConditionals translates if / else statement to found property value', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level} - {if data1.data2}{data1.data2}{end}', log), '{level} - bar')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals translates if / else statement to found property value and leave unmatched property key untouched', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level} - {if data1.data2}{data1.data2} ({msg}){end}', log), '{level} - bar ({msg})')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes non-terminated if statements', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level} - {if data1.data2}{data1.data2}', log), '{level} - {data1.data2}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes floating end statements', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level} - {data1.data2}{end}', log), '{level} - {data1.data2}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes floating end statements within translated if / end statements', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level} - {if msg}({msg}){end}{end}', log), '{level} - (foo)')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes if / end blocks if existent condition key does not match existent property key', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level}{if msg}{data1.data2}{end}', log), '{level}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes if / end blocks if non-existent condition key does not match existent property key', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level}{if foo}{msg}{end}', log), '{level}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes if / end blocks if existent condition key does not match non-existent property key', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level}{if msg}{foo}{end}', log), '{level}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes if / end blocks if non-existent condition key does not match non-existent property key', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level}{if foo}{bar}{end}', log), '{level}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes if / end blocks if nested condition key does not match property key', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{level}{if data1.msg}{data1.data2}{end}', log), '{level}')
|
||||
})
|
||||
|
||||
tap.test('interpretConditionals removes nested if / end statement blocks', async t => {
|
||||
const log = fastCopy(logData)
|
||||
t.equal(interpretConditionals('{if msg}{if data1.data2}{msg}{data1.data2}{end}{end}', log), 'foo{data1.data2}')
|
||||
})
|
||||
7
backend/node_modules/pino-pretty/lib/utils/is-object.js
generated
vendored
Normal file
7
backend/node_modules/pino-pretty/lib/utils/is-object.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = isObject
|
||||
|
||||
function isObject (input) {
|
||||
return Object.prototype.toString.apply(input) === '[object Object]'
|
||||
}
|
||||
10
backend/node_modules/pino-pretty/lib/utils/is-object.test.js
generated
vendored
Normal file
10
backend/node_modules/pino-pretty/lib/utils/is-object.test.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const isObject = require('./is-object')
|
||||
|
||||
tap.test('returns correct answer', async t => {
|
||||
t.equal(isObject({}), true)
|
||||
t.equal(isObject([]), false)
|
||||
t.equal(isObject(42), false)
|
||||
})
|
||||
14
backend/node_modules/pino-pretty/lib/utils/is-valid-date.js
generated
vendored
Normal file
14
backend/node_modules/pino-pretty/lib/utils/is-valid-date.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = isValidDate
|
||||
|
||||
/**
|
||||
* Checks if the argument is a JS Date and not 'Invalid Date'.
|
||||
*
|
||||
* @param {Date} date The date to check.
|
||||
*
|
||||
* @returns {boolean} true if the argument is a JS Date and not 'Invalid Date'.
|
||||
*/
|
||||
function isValidDate (date) {
|
||||
return date instanceof Date && !Number.isNaN(date.getTime())
|
||||
}
|
||||
16
backend/node_modules/pino-pretty/lib/utils/is-valid-date.test.js
generated
vendored
Normal file
16
backend/node_modules/pino-pretty/lib/utils/is-valid-date.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
const tap = require('tap')
|
||||
const isValidDate = require('./is-valid-date')
|
||||
|
||||
tap.test('returns true for valid dates', async t => {
|
||||
t.same(isValidDate(new Date()), true)
|
||||
})
|
||||
|
||||
tap.test('returns false for non-dates and invalid dates', async t => {
|
||||
t.plan(2)
|
||||
t.same(isValidDate('20210621'), false)
|
||||
t.same(isValidDate(new Date('2021-41-99')), false)
|
||||
})
|
||||
29
backend/node_modules/pino-pretty/lib/utils/join-lines-with-indentation.js
generated
vendored
Normal file
29
backend/node_modules/pino-pretty/lib/utils/join-lines-with-indentation.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = joinLinesWithIndentation
|
||||
|
||||
/**
|
||||
* @typedef {object} JoinLinesWithIndentationParams
|
||||
* @property {string} input The string to split and reformat.
|
||||
* @property {string} [ident] The indentation string. Default: ` ` (4 spaces).
|
||||
* @property {string} [eol] The end of line sequence to use when rejoining
|
||||
* the lines. Default: `'\n'`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Given a string with line separators, either `\r\n` or `\n`, add indentation
|
||||
* to all lines subsequent to the first line and rejoin the lines using an
|
||||
* end of line sequence.
|
||||
*
|
||||
* @param {JoinLinesWithIndentationParams} input
|
||||
*
|
||||
* @returns {string} A string with lines subsequent to the first indented
|
||||
* with the given indentation sequence.
|
||||
*/
|
||||
function joinLinesWithIndentation ({ input, ident = ' ', eol = '\n' }) {
|
||||
const lines = input.split(/\r?\n/)
|
||||
for (let i = 1; i < lines.length; i += 1) {
|
||||
lines[i] = ident + lines[i]
|
||||
}
|
||||
return lines.join(eol)
|
||||
}
|
||||
16
backend/node_modules/pino-pretty/lib/utils/join-lines-with-indentation.test.js
generated
vendored
Normal file
16
backend/node_modules/pino-pretty/lib/utils/join-lines-with-indentation.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const joinLinesWithIndentation = require('./join-lines-with-indentation')
|
||||
|
||||
tap.test('joinLinesWithIndentation adds indentation to beginning of subsequent lines', async t => {
|
||||
const input = 'foo\nbar\nbaz'
|
||||
const result = joinLinesWithIndentation({ input })
|
||||
t.equal(result, 'foo\n bar\n baz')
|
||||
})
|
||||
|
||||
tap.test('joinLinesWithIndentation accepts custom indentation, line breaks, and eol', async t => {
|
||||
const input = 'foo\nbar\r\nbaz'
|
||||
const result = joinLinesWithIndentation({ input, ident: ' ', eol: '^' })
|
||||
t.equal(result, 'foo^ bar^ baz')
|
||||
})
|
||||
3
backend/node_modules/pino-pretty/lib/utils/noop.js
generated
vendored
Normal file
3
backend/node_modules/pino-pretty/lib/utils/noop.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function noop () {}
|
||||
12
backend/node_modules/pino-pretty/lib/utils/noop.test.js
generated
vendored
Normal file
12
backend/node_modules/pino-pretty/lib/utils/noop.test.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const noop = require('./noop')
|
||||
|
||||
tap.test('is a function', async t => {
|
||||
t.type(noop, Function)
|
||||
})
|
||||
|
||||
tap.test('does nothing', async t => {
|
||||
t.equal(noop('stuff'), undefined)
|
||||
})
|
||||
153
backend/node_modules/pino-pretty/lib/utils/parse-factory-options.js
generated
vendored
Normal file
153
backend/node_modules/pino-pretty/lib/utils/parse-factory-options.js
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = parseFactoryOptions
|
||||
|
||||
const {
|
||||
LEVEL_NAMES
|
||||
} = require('../constants')
|
||||
const colors = require('../colors')
|
||||
const handleCustomLevelsOpts = require('./handle-custom-levels-opts')
|
||||
const handleCustomLevelsNamesOpts = require('./handle-custom-levels-names-opts')
|
||||
|
||||
/**
|
||||
* A `PrettyContext` is an object to be used by the various functions that
|
||||
* process log data. It is derived from the provided {@link PinoPrettyOptions}.
|
||||
* It may be used as a `this` context.
|
||||
*
|
||||
* @typedef {object} PrettyContext
|
||||
* @property {string} EOL The escape sequence chosen as the line terminator.
|
||||
* @property {string} IDENT The string to use as the indentation sequence.
|
||||
* @property {ColorizerFunc} colorizer A configured colorizer function.
|
||||
* @property {Array[Array<number, string>]} customColors A set of custom color
|
||||
* names associated with level numbers.
|
||||
* @property {object} customLevelNames A hash of level numbers to level names,
|
||||
* e.g. `{ 30: "info" }`.
|
||||
* @property {object} customLevels A hash of level names to level numbers,
|
||||
* e.g. `{ info: 30 }`.
|
||||
* @property {CustomPrettifiers} customPrettifiers A hash of custom prettifier
|
||||
* functions.
|
||||
* @property {object} customProperties Comprised of `customLevels` and
|
||||
* `customLevelNames` if such options are provided.
|
||||
* @property {string[]} errorLikeObjectKeys The key names in the log data that
|
||||
* should be considered as holding error objects.
|
||||
* @property {string[]} errorProps A list of error object keys that should be
|
||||
* included in the output.
|
||||
* @property {boolean} hideObject Indicates the prettifier should omit objects
|
||||
* in the output.
|
||||
* @property {string[]} ignoreKeys Set of log data keys to omit.
|
||||
* @property {string[]} includeKeys Opposite of `ignoreKeys`.
|
||||
* @property {boolean} levelFirst Indicates the level should be printed first.
|
||||
* @property {string} levelKey Name of the key in the log data that contains
|
||||
* the message.
|
||||
* @property {string} levelLabel Format token to represent the position of the
|
||||
* level name in the output string.
|
||||
* @property {MessageFormatString|MessageFormatFunction} messageFormat
|
||||
* @property {string} messageKey Name of the key in the log data that contains
|
||||
* the message.
|
||||
* @property {string|number} minimumLevel The minimum log level to process
|
||||
* and output.
|
||||
* @property {ColorizerFunc} objectColorizer
|
||||
* @property {boolean} singleLine Indicates objects should be printed on a
|
||||
* single output line.
|
||||
* @property {string} timestampKey The name of the key in the log data that
|
||||
* contains the log timestamp.
|
||||
* @property {boolean} translateTime Indicates if timestamps should be
|
||||
* translated to a human-readable string.
|
||||
* @property {boolean} useOnlyCustomProps
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {PinoPrettyOptions} options The user supplied object of options.
|
||||
*
|
||||
* @returns {PrettyContext}
|
||||
*/
|
||||
function parseFactoryOptions (options) {
|
||||
const EOL = options.crlf ? '\r\n' : '\n'
|
||||
const IDENT = ' '
|
||||
const {
|
||||
customPrettifiers,
|
||||
errorLikeObjectKeys,
|
||||
hideObject,
|
||||
levelFirst,
|
||||
levelKey,
|
||||
levelLabel,
|
||||
messageFormat,
|
||||
messageKey,
|
||||
minimumLevel,
|
||||
singleLine,
|
||||
timestampKey,
|
||||
translateTime
|
||||
} = options
|
||||
const errorProps = options.errorProps.split(',')
|
||||
const useOnlyCustomProps = typeof options.useOnlyCustomProps === 'boolean'
|
||||
? options.useOnlyCustomProps
|
||||
: (options.useOnlyCustomProps === 'true')
|
||||
const customLevels = handleCustomLevelsOpts(options.customLevels)
|
||||
const customLevelNames = handleCustomLevelsNamesOpts(options.customLevels)
|
||||
|
||||
let customColors
|
||||
if (options.customColors) {
|
||||
customColors = options.customColors.split(',').reduce((agg, value) => {
|
||||
const [level, color] = value.split(':')
|
||||
|
||||
const condition = useOnlyCustomProps
|
||||
? options.customLevels
|
||||
: customLevelNames[level] !== undefined
|
||||
const levelNum = condition
|
||||
? customLevelNames[level]
|
||||
: LEVEL_NAMES[level]
|
||||
const colorIdx = levelNum !== undefined
|
||||
? levelNum
|
||||
: level
|
||||
|
||||
agg.push([colorIdx, color])
|
||||
|
||||
return agg
|
||||
}, [])
|
||||
}
|
||||
|
||||
const customProperties = { customLevels, customLevelNames }
|
||||
if (useOnlyCustomProps === true && !options.customLevels) {
|
||||
customProperties.customLevels = undefined
|
||||
customProperties.customLevelNames = undefined
|
||||
}
|
||||
|
||||
const includeKeys = options.include !== undefined
|
||||
? new Set(options.include.split(','))
|
||||
: undefined
|
||||
const ignoreKeys = (!includeKeys && options.ignore)
|
||||
? new Set(options.ignore.split(','))
|
||||
: undefined
|
||||
|
||||
const colorizer = colors(options.colorize, customColors, useOnlyCustomProps)
|
||||
const objectColorizer = options.colorizeObjects
|
||||
? colorizer
|
||||
: colors(false, [], false)
|
||||
|
||||
return {
|
||||
EOL,
|
||||
IDENT,
|
||||
colorizer,
|
||||
customColors,
|
||||
customLevelNames,
|
||||
customLevels,
|
||||
customPrettifiers,
|
||||
customProperties,
|
||||
errorLikeObjectKeys,
|
||||
errorProps,
|
||||
hideObject,
|
||||
ignoreKeys,
|
||||
includeKeys,
|
||||
levelFirst,
|
||||
levelKey,
|
||||
levelLabel,
|
||||
messageFormat,
|
||||
messageKey,
|
||||
minimumLevel,
|
||||
objectColorizer,
|
||||
singleLine,
|
||||
timestampKey,
|
||||
translateTime,
|
||||
useOnlyCustomProps
|
||||
}
|
||||
}
|
||||
73
backend/node_modules/pino-pretty/lib/utils/prettify-error-log.js
generated
vendored
Normal file
73
backend/node_modules/pino-pretty/lib/utils/prettify-error-log.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyErrorLog
|
||||
|
||||
const {
|
||||
LOGGER_KEYS
|
||||
} = require('../constants')
|
||||
|
||||
const isObject = require('./is-object')
|
||||
const joinLinesWithIndentation = require('./join-lines-with-indentation')
|
||||
const prettifyObject = require('./prettify-object')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyErrorLogParams
|
||||
* @property {object} log The error log to prettify.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Given a log object that has a `type: 'Error'` key, prettify the object and
|
||||
* return the result. In other
|
||||
*
|
||||
* @param {PrettifyErrorLogParams} input
|
||||
*
|
||||
* @returns {string} A string that represents the prettified error log.
|
||||
*/
|
||||
function prettifyErrorLog ({ log, context }) {
|
||||
const {
|
||||
EOL: eol,
|
||||
IDENT: ident,
|
||||
errorProps: errorProperties,
|
||||
messageKey
|
||||
} = context
|
||||
const stack = log.stack
|
||||
const joinedLines = joinLinesWithIndentation({ input: stack, ident, eol })
|
||||
let result = `${ident}${joinedLines}${eol}`
|
||||
|
||||
if (errorProperties.length > 0) {
|
||||
const excludeProperties = LOGGER_KEYS.concat(messageKey, 'type', 'stack')
|
||||
let propertiesToPrint
|
||||
if (errorProperties[0] === '*') {
|
||||
// Print all sibling properties except for the standard exclusions.
|
||||
propertiesToPrint = Object.keys(log).filter(k => excludeProperties.includes(k) === false)
|
||||
} else {
|
||||
// Print only specified properties unless the property is a standard exclusion.
|
||||
propertiesToPrint = errorProperties.filter(k => excludeProperties.includes(k) === false)
|
||||
}
|
||||
|
||||
for (let i = 0; i < propertiesToPrint.length; i += 1) {
|
||||
const key = propertiesToPrint[i]
|
||||
if (key in log === false) continue
|
||||
if (isObject(log[key])) {
|
||||
// The nested object may have "logger" type keys but since they are not
|
||||
// at the root level of the object being processed, we want to print them.
|
||||
// Thus, we invoke with `excludeLoggerKeys: false`.
|
||||
const prettifiedObject = prettifyObject({
|
||||
log: log[key],
|
||||
excludeLoggerKeys: false,
|
||||
context: {
|
||||
...context,
|
||||
IDENT: ident + ident
|
||||
}
|
||||
})
|
||||
result = `${result}${ident}${key}: {${eol}${prettifiedObject}${ident}}${eol}`
|
||||
continue
|
||||
}
|
||||
result = `${result}${ident}${key}: ${log[key]}${eol}`
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
110
backend/node_modules/pino-pretty/lib/utils/prettify-error-log.test.js
generated
vendored
Normal file
110
backend/node_modules/pino-pretty/lib/utils/prettify-error-log.test.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const prettifyErrorLog = require('./prettify-error-log')
|
||||
const {
|
||||
ERROR_LIKE_KEYS,
|
||||
MESSAGE_KEY
|
||||
} = require('../constants')
|
||||
|
||||
const context = {
|
||||
EOL: '\n',
|
||||
IDENT: ' ',
|
||||
customPrettifiers: {},
|
||||
errorLikeObjectKeys: ERROR_LIKE_KEYS,
|
||||
errorProps: [],
|
||||
messageKey: MESSAGE_KEY
|
||||
}
|
||||
|
||||
tap.test('returns string with default settings', async t => {
|
||||
const err = Error('Something went wrong')
|
||||
const str = prettifyErrorLog({ log: err, context })
|
||||
t.ok(str.startsWith(' Error: Something went wrong'))
|
||||
})
|
||||
|
||||
tap.test('returns string with custom ident', async t => {
|
||||
const err = Error('Something went wrong')
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
IDENT: ' '
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: Something went wrong'))
|
||||
})
|
||||
|
||||
tap.test('returns string with custom eol', async t => {
|
||||
const err = Error('Something went wrong')
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
EOL: '\r\n'
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: Something went wrong\r\n'))
|
||||
})
|
||||
|
||||
tap.test('errorProperties', t => {
|
||||
t.test('excludes all for wildcard', async t => {
|
||||
const err = Error('boom')
|
||||
err.foo = 'foo'
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
errorProps: ['*']
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: boom'))
|
||||
t.equal(str.includes('foo: "foo"'), false)
|
||||
})
|
||||
|
||||
t.test('excludes only selected properties', async t => {
|
||||
const err = Error('boom')
|
||||
err.foo = 'foo'
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
errorProps: ['foo']
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: boom'))
|
||||
t.equal(str.includes('foo: foo'), true)
|
||||
})
|
||||
|
||||
t.test('ignores specified properties if not present', async t => {
|
||||
const err = Error('boom')
|
||||
err.foo = 'foo'
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
errorProps: ['foo', 'bar']
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: boom'))
|
||||
t.equal(str.includes('foo: foo'), true)
|
||||
t.equal(str.includes('bar'), false)
|
||||
})
|
||||
|
||||
t.test('processes nested objects', async t => {
|
||||
const err = Error('boom')
|
||||
err.foo = { bar: 'bar', message: 'included' }
|
||||
const str = prettifyErrorLog({
|
||||
log: err,
|
||||
context: {
|
||||
...context,
|
||||
errorProps: ['foo']
|
||||
}
|
||||
})
|
||||
t.ok(str.startsWith(' Error: boom'))
|
||||
t.equal(str.includes('foo: {'), true)
|
||||
t.equal(str.includes('bar: "bar"'), true)
|
||||
t.equal(str.includes('message: "included"'), true)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
49
backend/node_modules/pino-pretty/lib/utils/prettify-error.js
generated
vendored
Normal file
49
backend/node_modules/pino-pretty/lib/utils/prettify-error.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyError
|
||||
|
||||
const joinLinesWithIndentation = require('./join-lines-with-indentation')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyErrorParams
|
||||
* @property {string} keyName The key assigned to this error in the log object.
|
||||
* @property {string} lines The STRINGIFIED error. If the error field has a
|
||||
* custom prettifier, that should be pre-applied as well.
|
||||
* @property {string} ident The indentation sequence to use.
|
||||
* @property {string} eol The EOL sequence to use.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prettifies an error string into a multi-line format.
|
||||
*
|
||||
* @param {PrettifyErrorParams} input
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function prettifyError ({ keyName, lines, eol, ident }) {
|
||||
let result = ''
|
||||
const joinedLines = joinLinesWithIndentation({ input: lines, ident, eol })
|
||||
const splitLines = `${ident}${keyName}: ${joinedLines}${eol}`.split(eol)
|
||||
|
||||
for (let j = 0; j < splitLines.length; j += 1) {
|
||||
if (j !== 0) result += eol
|
||||
|
||||
const line = splitLines[j]
|
||||
if (/^\s*"stack"/.test(line)) {
|
||||
const matches = /^(\s*"stack":)\s*(".*"),?$/.exec(line)
|
||||
/* istanbul ignore else */
|
||||
if (matches && matches.length === 3) {
|
||||
const indentSize = /^\s*/.exec(line)[0].length + 4
|
||||
const indentation = ' '.repeat(indentSize)
|
||||
const stackMessage = matches[2]
|
||||
result += matches[1] + eol + indentation + JSON.parse(stackMessage).replace(/\n/g, eol + indentation)
|
||||
} else {
|
||||
result += line
|
||||
}
|
||||
} else {
|
||||
result += line
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
14
backend/node_modules/pino-pretty/lib/utils/prettify-error.test.js
generated
vendored
Normal file
14
backend/node_modules/pino-pretty/lib/utils/prettify-error.test.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const stringifySafe = require('fast-safe-stringify')
|
||||
const prettifyError = require('./prettify-error')
|
||||
|
||||
tap.test('prettifies error', t => {
|
||||
const error = Error('Bad error!')
|
||||
const lines = stringifySafe(error, Object.getOwnPropertyNames(error), 2)
|
||||
|
||||
const prettyError = prettifyError({ keyName: 'errorKey', lines, ident: ' ', eol: '\n' })
|
||||
t.match(prettyError, /\s*errorKey: {\n\s*"stack":[\s\S]*"message": "Bad error!"/)
|
||||
t.end()
|
||||
})
|
||||
35
backend/node_modules/pino-pretty/lib/utils/prettify-level.js
generated
vendored
Normal file
35
backend/node_modules/pino-pretty/lib/utils/prettify-level.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyLevel
|
||||
|
||||
const getPropertyValue = require('./get-property-value')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyLevelParams
|
||||
* @property {object} log The log object.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if the passed in log has a `level` value and returns a prettified
|
||||
* string for that level if so.
|
||||
*
|
||||
* @param {PrettifyLevelParams} input
|
||||
*
|
||||
* @returns {undefined|string} If `log` does not have a `level` property then
|
||||
* `undefined` will be returned. Otherwise, a string from the specified
|
||||
* `colorizer` is returned.
|
||||
*/
|
||||
function prettifyLevel ({ log, context }) {
|
||||
const {
|
||||
colorizer,
|
||||
customLevels,
|
||||
customLevelNames,
|
||||
levelKey
|
||||
} = context
|
||||
const prettifier = context.customPrettifiers?.level
|
||||
const output = getPropertyValue(log, levelKey)
|
||||
if (output === undefined) return undefined
|
||||
return prettifier ? prettifier(output) : colorizer(output, { customLevels, customLevelNames })
|
||||
}
|
||||
68
backend/node_modules/pino-pretty/lib/utils/prettify-level.test.js
generated
vendored
Normal file
68
backend/node_modules/pino-pretty/lib/utils/prettify-level.test.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const prettifyLevel = require('./prettify-level')
|
||||
const getColorizer = require('../colors')
|
||||
const {
|
||||
LEVEL_KEY
|
||||
} = require('../constants')
|
||||
|
||||
const context = {
|
||||
colorizer: getColorizer(),
|
||||
customLevelNames: undefined,
|
||||
customLevels: undefined,
|
||||
levelKey: LEVEL_KEY,
|
||||
customPrettifiers: undefined
|
||||
}
|
||||
|
||||
tap.test('returns `undefined` for unknown level', async t => {
|
||||
const colorized = prettifyLevel({
|
||||
log: {},
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(colorized, undefined)
|
||||
})
|
||||
|
||||
tap.test('returns non-colorized value for default colorizer', async t => {
|
||||
const log = {
|
||||
level: 30
|
||||
}
|
||||
const colorized = prettifyLevel({
|
||||
log,
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(colorized, 'INFO')
|
||||
})
|
||||
|
||||
tap.test('returns colorized value for color colorizer', async t => {
|
||||
const log = {
|
||||
level: 30
|
||||
}
|
||||
const colorizer = getColorizer(true)
|
||||
const colorized = prettifyLevel({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
colorizer
|
||||
}
|
||||
})
|
||||
t.equal(colorized, '\u001B[32mINFO\u001B[39m')
|
||||
})
|
||||
|
||||
tap.test('passes output through provided prettifier', async t => {
|
||||
const log = {
|
||||
level: 30
|
||||
}
|
||||
const colorized = prettifyLevel({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers: { level () { return 'modified' } }
|
||||
}
|
||||
})
|
||||
t.equal(colorized, 'modified')
|
||||
})
|
||||
63
backend/node_modules/pino-pretty/lib/utils/prettify-message.js
generated
vendored
Normal file
63
backend/node_modules/pino-pretty/lib/utils/prettify-message.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyMessage
|
||||
|
||||
const {
|
||||
LEVELS
|
||||
} = require('../constants')
|
||||
|
||||
const getPropertyValue = require('./get-property-value')
|
||||
const interpretConditionals = require('./interpret-conditionals')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyMessageParams
|
||||
* @property {object} log The log object with the message to colorize.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prettifies a message string if the given `log` has a message property.
|
||||
*
|
||||
* @param {PrettifyMessageParams} input
|
||||
*
|
||||
* @returns {undefined|string} If the message key is not found, or the message
|
||||
* key is not a string, then `undefined` will be returned. Otherwise, a string
|
||||
* that is the prettified message.
|
||||
*/
|
||||
function prettifyMessage ({ log, context }) {
|
||||
const {
|
||||
colorizer,
|
||||
customLevels,
|
||||
levelKey,
|
||||
levelLabel,
|
||||
messageFormat,
|
||||
messageKey,
|
||||
useOnlyCustomProps
|
||||
} = context
|
||||
if (messageFormat && typeof messageFormat === 'string') {
|
||||
const parsedMessageFormat = interpretConditionals(messageFormat, log)
|
||||
|
||||
const message = String(parsedMessageFormat).replace(
|
||||
/{([^{}]+)}/g,
|
||||
function (match, p1) {
|
||||
// return log level as string instead of int
|
||||
let level
|
||||
if (p1 === levelLabel && (level = getPropertyValue(log, levelKey)) !== undefined) {
|
||||
const condition = useOnlyCustomProps ? customLevels === undefined : customLevels[level] === undefined
|
||||
return condition ? LEVELS[level] : customLevels[level]
|
||||
}
|
||||
|
||||
// Parse nested key access, e.g. `{keyA.subKeyB}`.
|
||||
return getPropertyValue(log, p1) || ''
|
||||
})
|
||||
return colorizer.message(message)
|
||||
}
|
||||
if (messageFormat && typeof messageFormat === 'function') {
|
||||
const msg = messageFormat(log, messageKey, levelLabel)
|
||||
return colorizer.message(msg)
|
||||
}
|
||||
if (messageKey in log === false) return undefined
|
||||
if (typeof log[messageKey] !== 'string' && typeof log[messageKey] !== 'number' && typeof log[messageKey] !== 'boolean') return undefined
|
||||
return colorizer.message(log[messageKey])
|
||||
}
|
||||
187
backend/node_modules/pino-pretty/lib/utils/prettify-message.test.js
generated
vendored
Normal file
187
backend/node_modules/pino-pretty/lib/utils/prettify-message.test.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const prettifyMessage = require('./prettify-message')
|
||||
const getColorizer = require('../colors')
|
||||
const {
|
||||
LEVEL_KEY,
|
||||
LEVEL_LABEL
|
||||
} = require('../constants')
|
||||
const context = {
|
||||
colorizer: getColorizer(),
|
||||
levelKey: LEVEL_KEY,
|
||||
levelLabel: LEVEL_LABEL,
|
||||
messageKey: 'msg'
|
||||
}
|
||||
|
||||
tap.test('returns `undefined` if `messageKey` not found', async t => {
|
||||
const str = prettifyMessage({ log: {}, context })
|
||||
t.equal(str, undefined)
|
||||
})
|
||||
|
||||
tap.test('returns `undefined` if `messageKey` not string', async t => {
|
||||
const str = prettifyMessage({ log: { msg: {} }, context })
|
||||
t.equal(str, undefined)
|
||||
})
|
||||
|
||||
tap.test('returns non-colorized value for default colorizer', async t => {
|
||||
const colorizer = getColorizer()
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo' },
|
||||
context: { ...context, colorizer }
|
||||
})
|
||||
t.equal(str, 'foo')
|
||||
})
|
||||
|
||||
tap.test('returns non-colorized value for alternate `messageKey`', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { message: 'foo' },
|
||||
context: { ...context, messageKey: 'message' }
|
||||
})
|
||||
t.equal(str, 'foo')
|
||||
})
|
||||
|
||||
tap.test('returns colorized value for color colorizer', async t => {
|
||||
const colorizer = getColorizer(true)
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo' },
|
||||
context: { ...context, colorizer }
|
||||
})
|
||||
t.equal(str, '\u001B[36mfoo\u001B[39m')
|
||||
})
|
||||
|
||||
tap.test('returns colorized value for color colorizer for alternate `messageKey`', async t => {
|
||||
const colorizer = getColorizer(true)
|
||||
const str = prettifyMessage({
|
||||
log: { message: 'foo' },
|
||||
context: { ...context, messageKey: 'message', colorizer }
|
||||
})
|
||||
t.equal(str, '\u001B[36mfoo\u001B[39m')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule' },
|
||||
context: { ...context, messageFormat: '{context} - {msg}' }
|
||||
})
|
||||
t.equal(str, 'appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - missing prop', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { context: 'appModule' },
|
||||
context: { ...context, messageFormat: '{context} - {msg}' }
|
||||
})
|
||||
t.equal(str, 'appModule - ')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - levelLabel & useOnlyCustomProps false', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: {}
|
||||
}
|
||||
})
|
||||
t.equal(str, '[30] INFO appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - levelLabel & useOnlyCustomProps true', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 30: 'CHECK' },
|
||||
useOnlyCustomProps: true
|
||||
}
|
||||
})
|
||||
t.equal(str, '[30] CHECK appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - levelLabel & customLevels', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 123 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' }
|
||||
}
|
||||
})
|
||||
t.equal(str, '[123] CUSTOM appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - levelLabel, customLevels & useOnlyCustomProps', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 123 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' },
|
||||
useOnlyCustomProps: true
|
||||
}
|
||||
})
|
||||
t.equal(str, '[123] CUSTOM appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('returns message formatted by `messageFormat` option - levelLabel, customLevels & useOnlyCustomProps false', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 40 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' },
|
||||
useOnlyCustomProps: false
|
||||
}
|
||||
})
|
||||
t.equal(str, '[40] WARN appModule - foo')
|
||||
})
|
||||
|
||||
tap.test('`messageFormat` supports nested curly brackets', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{{level}}-{level}-{{level}-{level}}'
|
||||
}
|
||||
})
|
||||
t.equal(str, '{30}-30-{30-30}')
|
||||
})
|
||||
|
||||
tap.test('`messageFormat` supports nested object', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{request.url} - param: {request.params.process} - {msg}'
|
||||
}
|
||||
})
|
||||
t.equal(str, 'localhost/test - param: - foo')
|
||||
})
|
||||
|
||||
tap.test('`messageFormat` supports conditional blocks', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, req: { id: 'foo' } },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{level} | {if req.id}({req.id}){end}{if msg}{msg}{end}'
|
||||
}
|
||||
})
|
||||
t.equal(str, '30 | (foo)')
|
||||
})
|
||||
|
||||
tap.test('`messageFormat` supports function definition', async t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'incoming request' },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: (log, messageKey, levelLabel) => {
|
||||
let msg = log[messageKey]
|
||||
if (msg === 'incoming request') msg = `--> ${log.request.url}`
|
||||
return msg
|
||||
}
|
||||
}
|
||||
})
|
||||
t.equal(str, '--> localhost/test')
|
||||
})
|
||||
61
backend/node_modules/pino-pretty/lib/utils/prettify-metadata.js
generated
vendored
Normal file
61
backend/node_modules/pino-pretty/lib/utils/prettify-metadata.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyMetadata
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyMetadataParams
|
||||
* @property {object} log The log that may or may not contain metadata to
|
||||
* be prettified.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prettifies metadata that is usually present in a Pino log line. It looks for
|
||||
* fields `name`, `pid`, `hostname`, and `caller` and returns a formatted string using
|
||||
* the fields it finds.
|
||||
*
|
||||
* @param {PrettifyMetadataParams} input
|
||||
*
|
||||
* @returns {undefined|string} If no metadata is found then `undefined` is
|
||||
* returned. Otherwise, a string of prettified metadata is returned.
|
||||
*/
|
||||
function prettifyMetadata ({ log, context }) {
|
||||
const prettifiers = context.customPrettifiers
|
||||
let line = ''
|
||||
|
||||
if (log.name || log.pid || log.hostname) {
|
||||
line += '('
|
||||
|
||||
if (log.name) {
|
||||
line += prettifiers.name ? prettifiers.name(log.name) : log.name
|
||||
}
|
||||
|
||||
if (log.pid) {
|
||||
const prettyPid = prettifiers.pid ? prettifiers.pid(log.pid) : log.pid
|
||||
if (log.name && log.pid) {
|
||||
line += '/' + prettyPid
|
||||
} else {
|
||||
line += prettyPid
|
||||
}
|
||||
}
|
||||
|
||||
if (log.hostname) {
|
||||
// If `pid` and `name` were in the ignore keys list then we don't need
|
||||
// the leading space.
|
||||
line += `${line === '(' ? 'on' : ' on'} ${prettifiers.hostname ? prettifiers.hostname(log.hostname) : log.hostname}`
|
||||
}
|
||||
|
||||
line += ')'
|
||||
}
|
||||
|
||||
if (log.caller) {
|
||||
line += `${line === '' ? '' : ' '}<${prettifiers.caller ? prettifiers.caller(log.caller) : log.caller}>`
|
||||
}
|
||||
|
||||
if (line === '') {
|
||||
return undefined
|
||||
} else {
|
||||
return line
|
||||
}
|
||||
}
|
||||
111
backend/node_modules/pino-pretty/lib/utils/prettify-metadata.test.js
generated
vendored
Normal file
111
backend/node_modules/pino-pretty/lib/utils/prettify-metadata.test.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const prettifyMetadata = require('./prettify-metadata')
|
||||
const context = {
|
||||
customPrettifiers: {}
|
||||
}
|
||||
|
||||
tap.test('returns `undefined` if no metadata present', async t => {
|
||||
const str = prettifyMetadata({ log: {}, context })
|
||||
t.equal(str, undefined)
|
||||
})
|
||||
|
||||
tap.test('works with only `name` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo' }, context })
|
||||
t.equal(str, '(foo)')
|
||||
})
|
||||
|
||||
tap.test('works with only `pid` present', async t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234' }, context })
|
||||
t.equal(str, '(1234)')
|
||||
})
|
||||
|
||||
tap.test('works with only `hostname` present', async t => {
|
||||
const str = prettifyMetadata({ log: { hostname: 'bar' }, context })
|
||||
t.equal(str, '(on bar)')
|
||||
})
|
||||
|
||||
tap.test('works with only `name` & `pid` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234' }, context })
|
||||
t.equal(str, '(foo/1234)')
|
||||
})
|
||||
|
||||
tap.test('works with only `name` & `hostname` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', hostname: 'bar' }, context })
|
||||
t.equal(str, '(foo on bar)')
|
||||
})
|
||||
|
||||
tap.test('works with only `pid` & `hostname` present', async t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', hostname: 'bar' }, context })
|
||||
t.equal(str, '(1234 on bar)')
|
||||
})
|
||||
|
||||
tap.test('works with only `name`, `pid`, & `hostname` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', hostname: 'bar' }, context })
|
||||
t.equal(str, '(foo/1234 on bar)')
|
||||
})
|
||||
|
||||
tap.test('works with only `name` & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', caller: 'baz' }, context })
|
||||
t.equal(str, '(foo) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `pid` & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', caller: 'baz' }, context })
|
||||
t.equal(str, '(1234) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `hostname` & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { hostname: 'bar', caller: 'baz' }, context })
|
||||
t.equal(str, '(on bar) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `name`, `pid`, & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', caller: 'baz' }, context })
|
||||
t.equal(str, '(foo/1234) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `name`, `hostname`, & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.equal(str, '(foo on bar) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { caller: 'baz' }, context })
|
||||
t.equal(str, '<baz>')
|
||||
})
|
||||
|
||||
tap.test('works with only `pid`, `hostname`, & `caller` present', async t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.equal(str, '(1234 on bar) <baz>')
|
||||
})
|
||||
|
||||
tap.test('works with all four present', async t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.equal(str, '(foo/1234 on bar) <baz>')
|
||||
})
|
||||
|
||||
tap.test('uses prettifiers from passed prettifiers object', async t => {
|
||||
const prettifiers = {
|
||||
name (input) {
|
||||
return input.toUpperCase()
|
||||
},
|
||||
pid (input) {
|
||||
return input + '__'
|
||||
},
|
||||
hostname (input) {
|
||||
return input.toUpperCase()
|
||||
},
|
||||
caller (input) {
|
||||
return input.toUpperCase()
|
||||
}
|
||||
}
|
||||
const str = prettifyMetadata({
|
||||
log: { pid: '1234', hostname: 'bar', caller: 'baz', name: 'joe' },
|
||||
context: {
|
||||
customPrettifiers: prettifiers
|
||||
}
|
||||
})
|
||||
t.equal(str, '(JOE/1234__ on BAR) <BAZ>')
|
||||
})
|
||||
111
backend/node_modules/pino-pretty/lib/utils/prettify-object.js
generated
vendored
Normal file
111
backend/node_modules/pino-pretty/lib/utils/prettify-object.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyObject
|
||||
|
||||
const {
|
||||
LOGGER_KEYS
|
||||
} = require('../constants')
|
||||
|
||||
const stringifySafe = require('fast-safe-stringify')
|
||||
const joinLinesWithIndentation = require('./join-lines-with-indentation')
|
||||
const prettifyError = require('./prettify-error')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyObjectParams
|
||||
* @property {object} log The object to prettify.
|
||||
* @property {boolean} [excludeLoggerKeys] Indicates if known logger specific
|
||||
* keys should be excluded from prettification. Default: `true`.
|
||||
* @property {string[]} [skipKeys] A set of object keys to exclude from the
|
||||
* * prettified result. Default: `[]`.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prettifies a standard object. Special care is taken when processing the object
|
||||
* to handle child objects that are attached to keys known to contain error
|
||||
* objects.
|
||||
*
|
||||
* @param {PrettifyObjectParams} input
|
||||
*
|
||||
* @returns {string} The prettified string. This can be as little as `''` if
|
||||
* there was nothing to prettify.
|
||||
*/
|
||||
function prettifyObject ({
|
||||
log,
|
||||
excludeLoggerKeys = true,
|
||||
skipKeys = [],
|
||||
context
|
||||
}) {
|
||||
const {
|
||||
EOL: eol,
|
||||
IDENT: ident,
|
||||
customPrettifiers,
|
||||
errorLikeObjectKeys: errorLikeKeys,
|
||||
objectColorizer,
|
||||
singleLine
|
||||
} = context
|
||||
const keysToIgnore = [].concat(skipKeys)
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (excludeLoggerKeys === true) Array.prototype.push.apply(keysToIgnore, LOGGER_KEYS)
|
||||
|
||||
let result = ''
|
||||
|
||||
// Split object keys into two categories: error and non-error
|
||||
const { plain, errors } = Object.entries(log).reduce(({ plain, errors }, [k, v]) => {
|
||||
if (keysToIgnore.includes(k) === false) {
|
||||
// Pre-apply custom prettifiers, because all 3 cases below will need this
|
||||
const pretty = typeof customPrettifiers[k] === 'function'
|
||||
? customPrettifiers[k](v, k, log)
|
||||
: v
|
||||
if (errorLikeKeys.includes(k)) {
|
||||
errors[k] = pretty
|
||||
} else {
|
||||
plain[k] = pretty
|
||||
}
|
||||
}
|
||||
return { plain, errors }
|
||||
}, { plain: {}, errors: {} })
|
||||
|
||||
if (singleLine) {
|
||||
// Stringify the entire object as a single JSON line
|
||||
/* istanbul ignore else */
|
||||
if (Object.keys(plain).length > 0) {
|
||||
result += objectColorizer.greyMessage(stringifySafe(plain))
|
||||
}
|
||||
result += eol
|
||||
// Avoid printing the escape character on escaped backslashes.
|
||||
result = result.replace(/\\\\/gi, '\\')
|
||||
} else {
|
||||
// Put each object entry on its own line
|
||||
Object.entries(plain).forEach(([keyName, keyValue]) => {
|
||||
// custom prettifiers are already applied above, so we can skip it now
|
||||
let lines = typeof customPrettifiers[keyName] === 'function'
|
||||
? keyValue
|
||||
: stringifySafe(keyValue, null, 2)
|
||||
|
||||
if (lines === undefined) return
|
||||
|
||||
// Avoid printing the escape character on escaped backslashes.
|
||||
lines = lines.replace(/\\\\/gi, '\\')
|
||||
|
||||
const joinedLines = joinLinesWithIndentation({ input: lines, ident, eol })
|
||||
result += `${ident}${keyName}:${joinedLines.startsWith(eol) ? '' : ' '}${joinedLines}${eol}`
|
||||
})
|
||||
}
|
||||
|
||||
// Errors
|
||||
Object.entries(errors).forEach(([keyName, keyValue]) => {
|
||||
// custom prettifiers are already applied above, so we can skip it now
|
||||
const lines = typeof customPrettifiers[keyName] === 'function'
|
||||
? keyValue
|
||||
: stringifySafe(keyValue, null, 2)
|
||||
|
||||
if (lines === undefined) return
|
||||
|
||||
result += prettifyError({ keyName, lines, eol, ident })
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
152
backend/node_modules/pino-pretty/lib/utils/prettify-object.test.js
generated
vendored
Normal file
152
backend/node_modules/pino-pretty/lib/utils/prettify-object.test.js
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const colors = require('../colors')
|
||||
const prettifyObject = require('./prettify-object')
|
||||
const {
|
||||
ERROR_LIKE_KEYS
|
||||
} = require('../constants')
|
||||
|
||||
const context = {
|
||||
EOL: '\n',
|
||||
IDENT: ' ',
|
||||
customPrettifiers: {},
|
||||
errorLikeObjectKeys: ERROR_LIKE_KEYS,
|
||||
objectColorizer: colors(),
|
||||
singleLine: false
|
||||
}
|
||||
|
||||
tap.test('returns empty string if no properties present', async t => {
|
||||
const str = prettifyObject({ log: {}, context })
|
||||
t.equal(str, '')
|
||||
})
|
||||
|
||||
tap.test('works with single level properties', async t => {
|
||||
const str = prettifyObject({ log: { foo: 'bar' }, context })
|
||||
t.equal(str, ' foo: "bar"\n')
|
||||
})
|
||||
|
||||
tap.test('works with multiple level properties', async t => {
|
||||
const str = prettifyObject({ log: { foo: { bar: 'baz' } }, context })
|
||||
t.equal(str, ' foo: {\n "bar": "baz"\n }\n')
|
||||
})
|
||||
|
||||
tap.test('skips specified keys', async t => {
|
||||
const str = prettifyObject({
|
||||
log: { foo: 'bar', hello: 'world' },
|
||||
skipKeys: ['foo'],
|
||||
context
|
||||
})
|
||||
t.equal(str, ' hello: "world"\n')
|
||||
})
|
||||
|
||||
tap.test('ignores predefined keys', async t => {
|
||||
const str = prettifyObject({ log: { foo: 'bar', pid: 12345 }, context })
|
||||
t.equal(str, ' foo: "bar"\n')
|
||||
})
|
||||
|
||||
tap.test('ignores escaped backslashes in string values', async t => {
|
||||
const str = prettifyObject({ log: { foo_regexp: '\\[^\\w\\s]\\' }, context })
|
||||
t.equal(str, ' foo_regexp: "\\[^\\w\\s]\\"\n')
|
||||
})
|
||||
|
||||
tap.test('ignores escaped backslashes in string values (singleLine option)', async t => {
|
||||
const str = prettifyObject({
|
||||
log: { foo_regexp: '\\[^\\w\\s]\\' },
|
||||
context: {
|
||||
...context,
|
||||
singleLine: true
|
||||
}
|
||||
})
|
||||
t.equal(str, '{"foo_regexp":"\\[^\\w\\s]\\"}\n')
|
||||
})
|
||||
|
||||
tap.test('works with error props', async t => {
|
||||
const err = Error('Something went wrong')
|
||||
const serializedError = {
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
}
|
||||
const str = prettifyObject({ log: { error: serializedError }, context })
|
||||
t.ok(str.startsWith(' error:'))
|
||||
t.ok(str.includes(' "message": "Something went wrong",'))
|
||||
t.ok(str.includes(' Error: Something went wrong'))
|
||||
})
|
||||
|
||||
tap.test('customPrettifiers gets applied', async t => {
|
||||
const customPrettifiers = {
|
||||
foo: v => v.toUpperCase()
|
||||
}
|
||||
const str = prettifyObject({
|
||||
log: { foo: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers
|
||||
}
|
||||
})
|
||||
t.equal(str.startsWith(' foo: FOO'), true)
|
||||
})
|
||||
|
||||
tap.test('skips lines omitted by customPrettifiers', async t => {
|
||||
const customPrettifiers = {
|
||||
foo: () => { return undefined }
|
||||
}
|
||||
const str = prettifyObject({
|
||||
log: { foo: 'foo', bar: 'bar' },
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers
|
||||
}
|
||||
})
|
||||
t.equal(str.includes('bar: "bar"'), true)
|
||||
t.equal(str.includes('foo: "foo"'), false)
|
||||
})
|
||||
|
||||
tap.test('joined lines omits starting eol', async t => {
|
||||
const str = prettifyObject({
|
||||
log: { msg: 'doing work', calls: ['step 1', 'step 2', 'step 3'], level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
IDENT: '',
|
||||
customPrettifiers: {
|
||||
calls: val => '\n' + val.map(it => ' ' + it).join('\n')
|
||||
}
|
||||
}
|
||||
})
|
||||
t.equal(str, [
|
||||
'msg: "doing work"',
|
||||
'calls:',
|
||||
' step 1',
|
||||
' step 2',
|
||||
' step 3',
|
||||
''
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
tap.test('errors skips prettifiers', async t => {
|
||||
const customPrettifiers = {
|
||||
err: () => { return 'is_err' }
|
||||
}
|
||||
const str = prettifyObject({
|
||||
log: { err: Error('boom') },
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers
|
||||
}
|
||||
})
|
||||
t.equal(str.includes('err: is_err'), true)
|
||||
})
|
||||
|
||||
tap.test('errors skips prettifying if no lines are present', async t => {
|
||||
const customPrettifiers = {
|
||||
err: () => { return undefined }
|
||||
}
|
||||
const str = prettifyObject({
|
||||
log: { err: Error('boom') },
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers
|
||||
}
|
||||
})
|
||||
t.equal(str, '')
|
||||
})
|
||||
42
backend/node_modules/pino-pretty/lib/utils/prettify-time.js
generated
vendored
Normal file
42
backend/node_modules/pino-pretty/lib/utils/prettify-time.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = prettifyTime
|
||||
|
||||
const formatTime = require('./format-time')
|
||||
|
||||
/**
|
||||
* @typedef {object} PrettifyTimeParams
|
||||
* @property {object} log The log object with the timestamp to be prettified.
|
||||
* @property {PrettyContext} context The context object built from parsing
|
||||
* the options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prettifies a timestamp if the given `log` has either `time`, `timestamp` or custom specified timestamp
|
||||
* property.
|
||||
*
|
||||
* @param {PrettifyTimeParams} input
|
||||
*
|
||||
* @returns {undefined|string} If a timestamp property cannot be found then
|
||||
* `undefined` is returned. Otherwise, the prettified time is returned as a
|
||||
* string.
|
||||
*/
|
||||
function prettifyTime ({ log, context }) {
|
||||
const {
|
||||
timestampKey,
|
||||
translateTime: translateFormat
|
||||
} = context
|
||||
const prettifier = context.customPrettifiers?.time
|
||||
let time = null
|
||||
|
||||
if (timestampKey in log) {
|
||||
time = log[timestampKey]
|
||||
} else if ('timestamp' in log) {
|
||||
time = log.timestamp
|
||||
}
|
||||
|
||||
if (time === null) return undefined
|
||||
const output = translateFormat ? formatTime(time, translateFormat) : time
|
||||
|
||||
return prettifier ? prettifier(output) : `[${output}]`
|
||||
}
|
||||
227
backend/node_modules/pino-pretty/lib/utils/prettify-time.test.js
generated
vendored
Normal file
227
backend/node_modules/pino-pretty/lib/utils/prettify-time.test.js
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
'use strict'
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
const tap = require('tap')
|
||||
const prettifyTime = require('./prettify-time')
|
||||
const {
|
||||
TIMESTAMP_KEY
|
||||
} = require('../constants')
|
||||
const context = {
|
||||
timestampKey: TIMESTAMP_KEY,
|
||||
translateTime: true,
|
||||
customPrettifiers: {}
|
||||
}
|
||||
|
||||
tap.test('returns `undefined` if `time` or `timestamp` not in log', async t => {
|
||||
const str = prettifyTime({ log: {}, context })
|
||||
t.equal(str, undefined)
|
||||
})
|
||||
|
||||
tap.test('returns prettified formatted time from custom field', async t => {
|
||||
const log = { customtime: 1554642900000 }
|
||||
let str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
timestampKey: 'customtime'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[13:15:00.000]')
|
||||
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: false,
|
||||
timestampKey: 'customtime'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[1554642900000]')
|
||||
})
|
||||
|
||||
tap.test('returns prettified formatted time', async t => {
|
||||
let log = { time: 1554642900000 }
|
||||
let str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(str, '[13:15:00.000]')
|
||||
|
||||
log = { timestamp: 1554642900000 }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(str, '[13:15:00.000]')
|
||||
|
||||
log = { time: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(str, '[13:15:00.000]')
|
||||
|
||||
log = { timestamp: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context
|
||||
}
|
||||
})
|
||||
t.equal(str, '[13:15:00.000]')
|
||||
|
||||
log = { time: 1554642900000 }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: 'd mmm yyyy H:MM'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[7 Apr 2019 13:15]')
|
||||
|
||||
log = { timestamp: 1554642900000 }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: 'd mmm yyyy H:MM'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[7 Apr 2019 13:15]')
|
||||
|
||||
log = { time: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: 'd mmm yyyy H:MM'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[7 Apr 2019 13:15]')
|
||||
|
||||
log = { timestamp: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: 'd mmm yyyy H:MM'
|
||||
}
|
||||
})
|
||||
t.equal(str, '[7 Apr 2019 13:15]')
|
||||
})
|
||||
|
||||
tap.test('passes through value', async t => {
|
||||
let log = { time: 1554642900000 }
|
||||
let str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[1554642900000]')
|
||||
|
||||
log = { timestamp: 1554642900000 }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[1554642900000]')
|
||||
|
||||
log = { time: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[2019-04-07T09:15:00.000-04:00]')
|
||||
|
||||
log = { timestamp: '2019-04-07T09:15:00.000-04:00' }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[2019-04-07T09:15:00.000-04:00]')
|
||||
})
|
||||
|
||||
tap.test('handles the 0 timestamp', async t => {
|
||||
let log = { time: 0 }
|
||||
let str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[0]')
|
||||
|
||||
log = { timestamp: 0 }
|
||||
str = prettifyTime({
|
||||
log,
|
||||
context: {
|
||||
...context,
|
||||
translateTime: undefined
|
||||
}
|
||||
})
|
||||
t.equal(str, '[0]')
|
||||
})
|
||||
|
||||
tap.test('works with epoch as a number or string', (t) => {
|
||||
t.plan(3)
|
||||
const epoch = 1522431328992
|
||||
const asNumber = prettifyTime({
|
||||
log: { time: epoch, msg: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
translateTime: true
|
||||
}
|
||||
})
|
||||
const asString = prettifyTime({
|
||||
log: { time: `${epoch}`, msg: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
translateTime: true
|
||||
}
|
||||
})
|
||||
const invalid = prettifyTime({
|
||||
log: { time: '2 days ago', msg: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
translateTime: true
|
||||
}
|
||||
})
|
||||
t.same(asString, '[17:35:28.992]')
|
||||
t.same(asNumber, '[17:35:28.992]')
|
||||
t.same(invalid, '[2 days ago]')
|
||||
})
|
||||
|
||||
tap.test('uses custom prettifier', async t => {
|
||||
const str = prettifyTime({
|
||||
log: { time: 0 },
|
||||
context: {
|
||||
...context,
|
||||
customPrettifiers: {
|
||||
time () {
|
||||
return 'done'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.equal(str, 'done')
|
||||
})
|
||||
49
backend/node_modules/pino-pretty/lib/utils/split-property-key.js
generated
vendored
Normal file
49
backend/node_modules/pino-pretty/lib/utils/split-property-key.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = splitPropertyKey
|
||||
|
||||
/**
|
||||
* Splits the property key delimited by a dot character but not when it is preceded
|
||||
* by a backslash.
|
||||
*
|
||||
* @param {string} key A string identifying the property.
|
||||
*
|
||||
* @returns {string[]} Returns a list of string containing each delimited property.
|
||||
* e.g. `'prop2\.domain\.corp.prop2'` should return [ 'prop2.domain.com', 'prop2' ]
|
||||
*/
|
||||
function splitPropertyKey (key) {
|
||||
const result = []
|
||||
let backslash = false
|
||||
let segment = ''
|
||||
|
||||
for (let i = 0; i < key.length; i++) {
|
||||
const c = key.charAt(i)
|
||||
|
||||
if (c === '\\') {
|
||||
backslash = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (backslash) {
|
||||
backslash = false
|
||||
segment += c
|
||||
continue
|
||||
}
|
||||
|
||||
/* Non-escaped dot, push to result */
|
||||
if (c === '.') {
|
||||
result.push(segment)
|
||||
segment = ''
|
||||
continue
|
||||
}
|
||||
|
||||
segment += c
|
||||
}
|
||||
|
||||
/* Push last entry to result */
|
||||
if (segment.length) {
|
||||
result.push(segment)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
29
backend/node_modules/pino-pretty/lib/utils/split-property-key.test.js
generated
vendored
Normal file
29
backend/node_modules/pino-pretty/lib/utils/split-property-key.test.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
const tap = require('tap')
|
||||
const splitPropertyKey = require('./split-property-key')
|
||||
|
||||
tap.test('splitPropertyKey does not change key', async t => {
|
||||
const result = splitPropertyKey('data1')
|
||||
t.same(result, ['data1'])
|
||||
})
|
||||
|
||||
tap.test('splitPropertyKey splits nested key', async t => {
|
||||
const result = splitPropertyKey('data1.data2.data-3')
|
||||
t.same(result, ['data1', 'data2', 'data-3'])
|
||||
})
|
||||
|
||||
tap.test('splitPropertyKey splits nested keys ending with a dot', async t => {
|
||||
const result = splitPropertyKey('data1.data2.data-3.')
|
||||
t.same(result, ['data1', 'data2', 'data-3'])
|
||||
})
|
||||
|
||||
tap.test('splitPropertyKey splits nested escaped key', async t => {
|
||||
const result = splitPropertyKey('logging\\.domain\\.corp/operation.foo.bar-2')
|
||||
t.same(result, ['logging.domain.corp/operation', 'foo', 'bar-2'])
|
||||
})
|
||||
|
||||
tap.test('splitPropertyKey splits nested escaped key with special characters', async t => {
|
||||
const result = splitPropertyKey('logging\\.domain\\.corp/operation.!\t@#$%^&*()_+=-<>.bar\\.2')
|
||||
t.same(result, ['logging.domain.corp/operation', '!\t@#$%^&*()_+=-<>', 'bar.2'])
|
||||
})
|
||||
Reference in New Issue
Block a user