57 lines
1.6 KiB
JavaScript
57 lines
1.6 KiB
JavaScript
/**
|
|
* Tiny structured logger (JSON lines optional).
|
|
*/
|
|
|
|
const LEVELS = { debug: 10, info: 20, warn: 30, error: 40 }
|
|
const minLevel =
|
|
LEVELS[String(process.env.LOG_LEVEL || 'info').toLowerCase()] ?? LEVELS.info
|
|
|
|
function emit(level, scope, message, fields) {
|
|
if ((LEVELS[level] ?? 99) < minLevel) return
|
|
const line = {
|
|
ts: new Date().toISOString(),
|
|
level,
|
|
scope,
|
|
msg: message,
|
|
...(fields && typeof fields === 'object' ? fields : {}),
|
|
}
|
|
const text = process.env.LOG_JSON === '1' ? JSON.stringify(line) : formatPretty(line)
|
|
if (level === 'error') console.error(text)
|
|
else if (level === 'warn') console.warn(text)
|
|
else console.log(text)
|
|
}
|
|
|
|
function formatPretty(line) {
|
|
const extra = { ...line }
|
|
delete extra.ts
|
|
delete extra.level
|
|
delete extra.scope
|
|
delete extra.msg
|
|
const keys = Object.keys(extra)
|
|
const tail = keys.length ? ' ' + JSON.stringify(extra) : ''
|
|
return `${line.ts} [${line.level}] ${line.scope}: ${line.msg}${tail}`
|
|
}
|
|
|
|
function child(scope) {
|
|
return {
|
|
debug: (msg, fields) => emit('debug', scope, msg, fields),
|
|
info: (msg, fields) => emit('info', scope, msg, fields),
|
|
warn: (msg, fields) => emit('warn', scope, msg, fields),
|
|
error: (msg, fields) => emit('error', scope, msg, fields),
|
|
child: (sub) => child(`${scope}:${sub}`),
|
|
banner(fields = {}) {
|
|
const bar = '═'.repeat(56)
|
|
console.log(bar)
|
|
console.log(` ${fields.title || 'Pear App Server'}`)
|
|
for (const [k, v] of Object.entries(fields)) {
|
|
if (k === 'title') continue
|
|
console.log(` ${k}: ${v}`)
|
|
}
|
|
console.log(bar)
|
|
},
|
|
}
|
|
}
|
|
|
|
const logger = child('app')
|
|
export default logger
|