pino/lib/tools.js
2018-06-08 13:14:56 +02:00

215 lines
5.5 KiB
JavaScript

'use strict'
var format = require('quick-format-unescaped')
var util = require('util')
var serializers = require('pino-std-serializers')
function noop () {}
function copy (a, b) {
for (var k in b) { a[k] = b[k] }
return a
}
function asMetaWrapper (pretty, dest) {
const parsed = Symbol('parsedChindings')
if (!dest) {
dest = process.stdout
} else if (!dest.write) {
throw new Error('the destination must be writable')
}
return {
[Symbol.for('needsMetadata')]: true,
lastLevel: 0,
lastMsg: null,
lastObj: null,
lastLogger: null,
write (chunk) {
var chindings = this.lastLogger[parsed]
if (!chindings) {
chindings = JSON.parse('{"v":1' + this.lastLogger.chindings + '}')
this.lastLogger[parsed] = 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 defineLevelsProperty (onObject, levels) {
Object.defineProperty(onObject, 'levels', {
value: {
values: copy({}, levels.levels),
labels: copy({}, levels.nums)
},
enumerable: true
})
Object.defineProperty(onObject.levels.values, 'silent', {value: Infinity})
Object.defineProperty(onObject.levels.labels, Infinity, {value: 'silent'})
}
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 l = str.length
var point = 255
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
}
}
if (last === 0) {
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
var hasObj = obj !== undefined && obj !== null
var objError = hasObj && obj instanceof Error
msg = !msg && objError ? obj.message : msg || undefined
var data = this._lscache[num] + time
if (msg !== undefined) {
data += this.messageKeyString + asString('' + msg)
}
// we need the child bindings added to the output first so that logged
// objects can take precedence when JSON.parse-ing the resulting log line
data = data + this.chindings
var value
if (hasObj) {
var notHasOwnProperty = obj.hasOwnProperty === undefined
if (objError) {
data += ',"type":"Error","stack":' + this.stringify(obj.stack)
}
// if global serializer is set, call it first
if (this.serializers[Symbol.for('pino.*')]) {
obj = this.serializers[Symbol.for('pino.*')](obj)
}
for (var key in obj) {
value = obj[key]
if ((notHasOwnProperty || obj.hasOwnProperty(key)) && value !== undefined) {
value = (this.stringifiers[key] || this.stringify)(this.serializers[key] ? this.serializers[key](value) : value)
if (value !== undefined) {
data += ',"' + key + '":' + value
}
}
}
}
return data + this.end
}
function asChindings (that, bindings) {
if (!bindings) {
throw Error('missing bindings for child Pino')
}
var key
var value
var data = that.chindings
if (that.serializers[Symbol.for('pino.*')]) {
bindings = that.serializers[Symbol.for('pino.*')](bindings)
}
for (key in bindings) {
value = bindings[key]
if (key !== 'level' && key !== 'serializers' && bindings.hasOwnProperty(key) && value !== undefined) {
value = that.serializers[key] ? that.serializers[key](value) : value
data += ',"' + key + '":' + (that.stringifiers[key] || that.stringify)(value)
}
}
return data
}
module.exports = {
copy,
defineLevelsProperty,
noop,
getPrettyStream,
asChindings,
asJson,
genLog
}