UNPKG

laabr

Version:

well-formatted, extendable pino logger for hapi.js

182 lines (145 loc) 3.58 kB
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