pino/lib/tools.js

216 lines
5.4 KiB
JavaScript

'use strict'
const format = require('quick-format-unescaped')
const util = require('util')
const serializers = require('pino-std-serializers')
const {
lsCacheSym,
chindingsSym,
parsedChindingsSym,
needsMetadataGsym,
wildcardGsym
} = require('./symbols')
function noop () {}
function copy (a, b) {
for (var k in b) { a[k] = b[k] }
return a
}
function asMetaWrapper (pretty, dest) {
if (!dest) {
dest = process.stdout
} else if (!dest.write) {
throw new Error('the destination must be writable')
}
return {
[needsMetadataGsym]: true,
lastLevel: 0,
lastMsg: null,
lastObj: null,
lastLogger: null,
write (chunk) {
var chindings = this.lastLogger[parsedChindingsSym]
if (!chindings) {
chindings = JSON.parse('{"v":1' + this.lastLogger[chindingsSym] + '}')
this.lastLogger[parsedChindingsSym] = chindings
}
const obj = Object.assign({
level: this.lastLevel,
msg: this.lastMsg,
time: this.lastTime
}, chindings, this.lastObj)
const formatted = pretty(obj)
if (formatted === undefined) return
dest.write(formatted)
}
}
}
function countInterp (s, i) {
var n = 0
var pos = 0
while (true) {
pos = s.indexOf(i, pos)
if (pos >= 0) {
++n
pos += 2
} else break
}
return n
}
function genLog (z) {
return function LOG (a, b, c, d, e, f, g, h, i, j, k) {
var l = 0
var m = null
var n = null
var o
var p
if (typeof a === 'object' && a !== null) {
m = a
n = [b, c, d, e, f, g, h, i, j, k]
l = 1
if (m.method && m.headers && m.socket) {
m = serializers.mapHttpRequest(m)
} else if (typeof m.setHeader === 'function') {
m = serializers.mapHttpResponse(m)
}
} else {
n = [a, b, c, d, e, f, g, h, i, j, k]
}
p = n.length = arguments.length - l
if (p > 1) {
l = typeof a === 'string' ? countInterp(a, '%j') : 0
if (l) {
n.length = l + countInterp(a, '%d') + countInterp(a, '%s') + 1
o = `${util.format.apply(null, n)}`
} else {
o = format(n, this.formatOpts)
}
} else if (p === 1) {
o = n[0]
}
this.write(m, o, z)
}
}
function getPrettyStream (opts, prettifier, dest) {
if (prettifier && typeof prettifier === 'function') {
return asMetaWrapper(prettifier(opts), dest)
}
try {
var prettyFactory = require('pino-pretty')
return asMetaWrapper(prettyFactory(opts), dest)
} catch (e) {
throw Error('Missing `pino-pretty` module: `pino-pretty` must be installed separately')
}
}
// magically escape strings for json
// relying on their charCodeAt
// everything below 32 needs JSON.stringify()
// 34 and 92 happens all the time, so we
// have a fast case for them
function asString (str) {
var result = ''
var last = 0
var found = false
var point = 255
const l = str.length
if (l > 42) {
return JSON.stringify(str)
}
for (var i = 0; i < l && point >= 32; i++) {
point = str.charCodeAt(i)
if (point === 34 || point === 92) {
result += str.slice(last, i) + '\\'
last = i
found = true
}
}
if (!found) {
result = str
} else {
result += str.slice(last)
}
return point < 32 ? JSON.stringify(str) : '"' + result + '"'
}
function asJson (obj, msg, num, time) {
// to catch both null and undefined
const hasObj = obj !== undefined && obj !== null
const objError = hasObj && obj instanceof Error
msg = !msg && objError === true ? obj.message : msg || undefined
const { serializers, stringify, stringifiers, end, messageKeyString } = this
const chindings = this[chindingsSym]
var data = this[lsCacheSym][num] + time
if (msg !== undefined) {
data += messageKeyString + asString('' + msg)
}
// we need the child bindings added to the output first so instance logged
// objects can take precedence when JSON.parse-ing the resulting log line
data = data + chindings
var value
if (hasObj === true) {
var notHasOwnProperty = obj.hasOwnProperty === undefined
if (objError === true) {
data += ',"type":"Error","stack":' + stringify(obj.stack)
}
// if global serializer is set, call it first
if (serializers[wildcardGsym]) {
obj = serializers[wildcardGsym](obj)
}
for (var key in obj) {
value = obj[key]
if ((notHasOwnProperty || obj.hasOwnProperty(key)) && value !== undefined) {
value = (stringifiers[key] || stringify)(serializers[key] ? serializers[key](value) : value)
if (value !== undefined) {
data += ',"' + key + '":' + value
}
}
}
}
return data + end
}
function asChindings (instance, bindings) {
if (!bindings) {
throw Error('missing bindings for child Pino')
}
var key
var value
var data = instance[chindingsSym]
const { serializers, stringifiers, stringify } = instance
if (serializers[wildcardGsym]) {
bindings = serializers[wildcardGsym](bindings)
}
for (key in bindings) {
value = bindings[key]
const valid = key !== 'level' &&
key !== 'serializers' &&
bindings.hasOwnProperty(key) &&
value !== undefined
if (valid === true) {
value = serializers[key] ? serializers[key](value) : value
data += ',"' + key + '":' + (stringifiers[key] || stringify)(value)
}
}
return data
}
module.exports = {
copy,
noop,
getPrettyStream,
asChindings,
asJson,
genLog
}