koa-logger源码解析
以GET申请“/”为例子,koa-logger
会打印以下日志:
<-- GET /GET / - 790ms --> GET / 200 803ms 185b
分为是申请与响应的日志
// koa-logger 主函数function dev (opts) { // print函数,默认参数为空时是调用console.log,如果有transporter选项,则调用transporter函数代替 const print = (function () { let transporter if (typeof opts === 'function') { transporter = opts } else if (opts && opts.transporter) { transporter = opts.transporter } return function printFunc (...args) { // 留神:这里做了格局说明符替换 const str = util.format(...args) if (transporter) { transporter(str, args) } else { console.log(...args) } } }()) return async function logger (ctx, next) { // request const start = ctx[Symbol.for('request-received.startTime')] ? ctx[Symbol.for('request-received.startTime')].getTime() : Date.now() // 打印申请日志 print(' ' + chalk.gray('<--') + ' ' + chalk.bold('%s') + ' ' + chalk.gray('%s'), ctx.method, ctx.originalUrl) try { await next() } catch (err) { // log uncaught downstream errors log(print, ctx, start, null, err) throw err } // calculate the length of a streaming response // by intercepting the stream with a counter. // only necessary if a content-length header is currently not set. // 通过应用计数器拦挡流来计算响应流的长度。只有在以后没有设置Content-Length的响应报头时才须要。 const length = ctx.response.length const body = ctx.body let counter if (length == null && body && body.readable) { ctx.body = body .pipe(counter = Counter()) .on('error', ctx.onerror) } // log when the response is finished or closed, // whichever happens first. // 记录响应实现或敞开的工夫,以先产生的工夫为准。个别都是触发finish事件 const res = ctx.res const onfinish = done.bind(null, 'finish') const onclose = done.bind(null, 'close') // 重点:判断一个流申请是否完结 res.once('finish', onfinish) res.once('close', onclose) function done (event) { res.removeListener('finish', onfinish) res.removeListener('close', onclose) // 打印 申请形式 门路 状态码 响应工夫 报文长度 log(print, ctx, start, counter ? counter.length : length, null, event) } }}
还有个logger辅助函数:
/** * Log helper. 封装的输入打点数据的辅助函数 */function log (print, ctx, start, len, err, event) { // 从err获取响应的状态码 // 以下字段比方err.isBoom、err.output.statusCode、err.status等都是依据业务来的 // 个别业务都有对立的解决响应的中间件 // 留神500、404的解决辨别 const status = err ? (err.isBoom ? err.output.statusCode : err.status || 500) : (ctx.status || 404) // set the color of the status code; // 依据不同状态码区间,1xx、2xx、3xx、4xx、5xx,映射抉择不必色彩输入加以辨别 const s = status / 100 | 0 // eslint-disable-next-line const color = colorCodes.hasOwnProperty(s) ? colorCodes[s] : colorCodes[0] // get the human readable response length let length // 204、205、304非凡解决 if (~[204, 205, 304].indexOf(status)) { length = '' } else if (len == null) { length = '-' } else { // 借助bytes库,计算响应内容大小、输入相似2b、2kb length = bytes(len).toLowerCase() } const upstream = err ? chalk.red('xxx') : event === 'close' ? chalk.yellow('-x-') : chalk.gray('-->') print(' ' + upstream + ' ' + chalk.bold('%s') + ' ' + chalk.gray('%s') + ' ' + chalk[color]('%s') + ' ' + chalk.gray('%s') + ' ' + chalk.gray('%s'), ctx.method, ctx.originalUrl, status, time(start), length)}/** * Show the response time in a human readable format. * In milliseconds if less than 10 seconds, * in seconds otherwise. */function time (start) { const delta = Date.now() - start return humanize(delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's')}
总结
这个包代码很简略,不到200行代码,性能也很简略,须要拓展须要手动定制。