brf/server/lib/pino_transport_console.ts
2025-12-13 21:12:08 +01:00

99 lines
2.6 KiB
TypeScript

import util from 'node:util'
import chalk from 'chalk'
import _ from 'lodash'
// @ts-ignore
import highlightStack from '@bmp/highlight-stack'
const LEVELS: Record<string, string> = {
default: 'USERLVL',
60: 'FATAL',
50: 'ERROR',
40: 'WARN',
30: 'INFO',
20: 'DEBUG',
10: 'TRACE',
}
const COLORS: Record<string, any> = {
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: number) {
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)
}
}
interface BaseLineObject {
level: number
time: number
pid: number
reqId: string
msg: string
}
interface ErrorLineObject extends BaseLineObject {
level: 50
err: ANY
}
interface IncomingRequestLineObject extends BaseLineObject {
msg: 'incoming request'
req: Record<string, any>
}
interface RequestCompletedLineObject extends BaseLineObject {
msg: 'request completed'
res: Record<string, any>
responseTime: number
}
type LineObject = ErrorLineObject | IncomingRequestLineObject | RequestCompletedLineObject | BaseLineObject
export default {
write(line: string) {
const obj: LineObject = JSON.parse(line)
if (obj.msg === 'incoming request') {
requests.set(obj.reqId, (obj as IncomingRequestLineObject).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 as RequestCompletedLineObject).res.statusCode)} ${(
obj as RequestCompletedLineObject
).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 as ErrorLineObject).err.status < 500) return
process.stdout.write(
`${COLORS[obj.level](LEVELS[obj.level] || LEVELS.default)} ${highlightStack((obj as ErrorLineObject).err.stack)}\n`,
)
const details = _.omit((obj as ErrorLineObject).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`)
}
},
}