123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /**
- * Module dependencies.
- */
- 'use strict'
- const Counter = require('passthrough-counter')
- const humanize = require('humanize-number')
- const bytes = require('bytes')
- const chalk = require('chalk')
- const util = require('util')
- /**
- * Expose logger.
- */
- module.exports = dev
- /**
- * Color map.
- */
- const colorCodes = {
- 7: 'magenta',
- 5: 'red',
- 4: 'yellow',
- 3: 'cyan',
- 2: 'green',
- 1: 'green',
- 0: 'yellow'
- }
- /**
- * Development logger.
- */
- function dev (opts) {
- // print to console helper.
- 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.
- 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.
- 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)
- }
- }
- }
- /**
- * Log helper.
- */
- function log (print, ctx, start, len, err, event) {
- // get the status code of the response
- const status = err
- ? (err.isBoom ? err.output.statusCode : err.status || 500)
- : (ctx.status || 404)
- // set the color of the status code;
- 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
- if (~[204, 205, 304].indexOf(status)) {
- length = ''
- } else if (len == null) {
- length = '-'
- } else {
- 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')
- }
|