laabr
Version:
well-formatted, extendable pino logger for hapi.js
182 lines (145 loc) • 3.58 kB
JavaScript
const { IncomingMessage } = require('http')
const { Readable } = require('stream')
const { URL } = require('url')
const get = require('lodash.get')
const set = require('lodash.set')
const pino = require('pino')
const utils = require('./utils')
const validator = require('./validator')
/**
* @type Object.<Function>
* @public
*
* Collection of tokens.
*/
const tokens = {}
/**
* @function
* @public
*
* Assign new token to the collection.
*
* @param {string} key The name of the token
* @param {Function} token The token callback
*/
function assign (key, token) {
validator('tokenLabel', key)
validator('token', token)
tokens[key] = token
}
/**
* @function
* @public
*
* Initialize tokens passed as options to plugin.
*
* @param {Object} [optionTokens = {}] The defined tokens
*/
function init (optionTokens = {}) {
Object.keys(optionTokens).forEach((key) => assign(key, optionTokens[key]))
}
assign('pid', data => (
data.pid
))
assign('tags', data => (
data.tags || []
))
assign('level', (data, colors, field) => {
if (field === 'code') {
return colors.level(data.level)
}
return colors.level(pino.levels.labels[data.level])
})
assign('time', (data, colors, field) => {
const date = new Date(data.time)
let ts = data.time
switch (field) {
case 'iso':
ts = date.toISOString()
break
case 'utc':
ts = date.toUTCString()
break
}
return colors.dim(ts)
})
assign('message', (data, colors, field = 'msg') => (
get(data, field) || data.msg || data.data
))
assign('get', (data, colors, field) => (
get(data, field)
))
assign('error', (data, colors, field = 'message') => {
if (!get(data, 'err') && get(data, 'data.err')) {
data = data.data
}
if (!get(data, 'err.source')) {
set(data, 'err.source', utils.getErrorSource(data.err))
}
return get(data.err, field)
})
assign('environment', (data, colors, field = 'NODE_ENV') => (
process.env[field]
))
assign('requestId', data => (
data.req && data.req.id
))
assign('responseTime', data => (
data.responseTime
))
assign('res', (data, colors, field) => (
data.res && data.res.headers && data.res.headers[field]
))
assign('req', (data, colors, field) => (
data.req && data.req.headers && data.req.headers[field]
))
assign('status', (data, colors) => (
colors.status(data.res && data.res.statusCode)
))
assign('method', (data, colors) => (
colors.status(data.req && data.req.method && data.req.method.toUpperCase())
))
assign('payload', data => {
const rawFormat = [Readable, IncomingMessage].find(x => data.payload instanceof x)
if (rawFormat) {
return `[${rawFormat.name}]`
}
if (data.payload instanceof Buffer) {
return data.payload.toString()
}
return JSON.stringify(data.payload || {})
})
assign('remoteAddress', data => {
if (!data.req) {
return undefined
}
const rawKey = Object.getOwnPropertySymbols(data.req)[0]
return data.req.remoteAddress || (rawKey && data.req[rawKey].remoteAddress)
})
assign('remotePort', data => (
data.req && data.req.remotePort
))
assign('url', data => {
if (data.req && data.req.url) {
const href = data.req.url.href || data.req.url
try {
return new URL(href).pathname
} catch {
return href
}
}
})
assign('host', (data, colors, field = 'host') => {
switch (field) {
case 'uri':
case 'address':
case 'port':
case 'host':
case 'protocol':
return data[field]
default:
return undefined
}
})
Object.assign(tokens, { assign, init })
module.exports = tokens