import util from 'node:util' import chalk from 'chalk' import _ from 'lodash' import highlightStack from '@bmp/highlight-stack' const LEVELS = { default: 'USERLVL', 60: 'FATAL', 50: 'ERROR', 40: 'WARN', 30: 'INFO', 20: 'DEBUG', 10: 'TRACE', } const COLORS = { 60: chalk.bgRed, 50: chalk.red, 40: chalk.yellow, 30: chalk.green, 20: chalk.blue, 10: chalk.grey, } const requests = new Map() function colorStatusCode(statusCode) { if (statusCode < 300) { return chalk.bold.green(statusCode) } else if (statusCode < 400) { return chalk.bold.blue(statusCode) } else if (statusCode < 500) { return chalk.bold.yellow(statusCode) } else { return chalk.bold.red(statusCode) } } export default { write(line) { const obj = JSON.parse(line) if (obj.msg === 'incoming request') { requests.set(obj.reqId, obj.req) } else if (obj.msg === 'request completed') { const req = requests.get(obj.reqId) requests.delete(obj.reqId) process.stdout.write( `${chalk.bold(req.method)} ${req.url} ${colorStatusCode(obj.res.statusCode)} ${obj.responseTime.toFixed( 3, )} ms\n`, ) } else if (obj.level === 50) { // TODO figure out if there is a way to get the error instances here... console.log(Error) and util.inspect(Error) // looks better than the serialized errors if (obj.err.status < 500) return process.stdout.write( `${COLORS[obj.level](LEVELS[obj.level] || LEVELS.default)} ${highlightStack(obj.err.stack)}\n`, ) const details = _.omit(obj.err, ['type', 'message', 'stack']) if (!_.isEmpty(details)) { process.stdout.write(`${chalk.red('Details')} ${util.inspect(details, false, 4, true)}\n`) } } else { process.stdout.write(`${COLORS[obj.level](LEVELS[obj.level] || LEVELS.default)} ${obj.msg}\n`) } }, }