UNPKG

modernirc

Version:

IRC library for creating modern IRC bots

185 lines (172 loc) 5.11 kB
/** * Internal Logger * * Console, file and HTTP capability */ import http from 'node:http' import https from 'node:https' import qs from 'node:querystring' import { join } from 'node:path' import { createWriteStream } from 'node:fs' import process from 'node:process' function defaultPrettyFormat({ name, date, level, text }) { return `[${date}] (${level.toUpperCase()}) ${name}:${text}\n` } function createConsoleTransporter(name, options = {}) { const { pretty = false, formatter = null } = options return { output(_level, _raw) { if (pretty) { process.stdout.write( // (formatter || defaultPrettyFormat)(`[${new Date().toISOString()}] (${_level.toUpperCase()}) ${name}:${_raw}\n`) (formatter || defaultPrettyFormat)({ name, date: new Date().toISOString(), level: _level, text: _raw, }) ) } else { process.stdout.write(`${JSON.stringify({ date: new Date().toISOString(), level: _level.toUpperCase(), name, message: _raw, })}\n`) } }, } } function createFileTransporter(name, options = {}) { const { pretty = false, path = '/var/log', formatter = null } = options const fout = createWriteStream(join(path, `${name}.log`)) return { output(_level, _raw) { if (pretty) { fout.write( (formatter || defaultPrettyFormat)({ name, date: new Date().toISOString(), level: _level, text: _raw, }) ) } else { fout.write(`${JSON.stringify({ date: new Date().toISOString(), level: _level.toUpperCase(), name, message: _raw, })}\n`) } }, } } function createHttpTransporter(name, options = {}) { const { target, method = 'post', formatter = null, contentType = 'application/json', headers = {}, } = options return { output(_level, _raw) { let body = { date: new Date().toISOString(), name, level: _level.toUpperCase(), text: _raw, } if (typeof formatter === 'function') { body = formatter(body) } if (contentType === 'application/json') { body = JSON.stringify(body) } else if (contentType === 'application/x-www-form-urlencoded') { body = qs.stringify(body) } else { throw new Error('invalid contentType') } const intf = target.startsWith('https://') ? https : http return new Promise((resolve, reject) => { const req = intf.request(target, { method, headers: { 'Content-Type': contentType, ...headers, }, }, (res) => { if (res.statusCode < 300) { resolve() } else { reject(new Error(res.statusMessage)) } }) req.on('error', reject) req.end(body) }) }, } } /** * Creates a new logger * @param options {object} * @returns {object} */ export function createLogger(options = {}) { const { level = 'info', levels = ['error', 'warning', 'info', 'log', 'debug'], transports = [{ type: 'console', level: 'debug', opts: { pretty: true } }], name = 'app', } = options const indexOfCurrentLevel = levels.indexOf(level) // const _transporters = { // console: createConsoleTransporter(name, transports.find((t) => t.type === 'console')?.opts ?? {}), // file: createFileTransporter(name, transports.find((t) => t.type === 'file')?.opts ?? {}), // } const _transporters = transports.map((meta) => { if (meta.type === 'console') { return createConsoleTransporter(name, meta.opts) } if (meta.type === 'file') { return createFileTransporter(name, meta.opts) } if (meta.type === 'http') { return createHttpTransporter(name, meta.opts) } if (!meta.type || typeof meta.builder === 'function') { return meta.builder(name, meta.opts) } throw new Error(`unknown transport type: ${meta.type}`) }) return new Proxy({ _options: options }, { get(target, p) { if (levels.includes(p.toLowerCase())) { return (str) => { const indexOfP = levels.indexOf(p) for (let i = 0; i < transports.length; i++) { let _transporterLevel = levels.indexOf(transports[i].level?.toLowerCase()) if (_transporterLevel === -1) { _transporterLevel = indexOfCurrentLevel } if (indexOfP <= _transporterLevel) { const _transport = _transporters[i] _transport.output(p, str) } } } } else if (p.toLowerCase() === 'child') { // Create a child logger with a specific name return (childName) => createLogger({ ...options, name: `${name}/${childName}`, }) } else if (p.toLowerCase() === 'options') { return target._options } return undefined }, }) }