skarif2/logger

View on GitHub
index.js

Summary

Maintainability
A
0 mins
Test Coverage
/*!
 * logger
 * Copyright(c) 2019 Sk Arif
 * MIT Licensed
 */
var util = require('util')
var consola = require('consola')
var onFinished = require('on-finished')

/**
 * log req and res body with request details
 *
 * @return {Function} middleware
 * @public
 */
function logger (req, res, next) {
  req.startAt = process.hrtime()
  var response = res.app.response.send

  res.app.response.send = function send(body) {
    response.call(this, body)
    if (body) {
      try {
        res.body = JSON.parse(body)
      } catch (e) {
        res.body = body
      }
    }
  }

  onFinished(res, function (err, res) {
    log(err, req, res)
  })

  next()
}

function log (err, req, res) {
  if (err) {
    consola.warn(err)
    return
  }

  var diff = process.hrtime(req.startAt)
  var time = diff[0] * 1e3 + diff[1] * 1e-6
  res.responseTime = time.toFixed(2)

  logObj('req', res.statusCode, reqObj(req))
  logObj('res', res.statusCode, resObj(res))
  logError(res)
  logRequest(req, res)
}

/**
 * custom req object
 * @private
 */
function reqObj (req) {
  return {
    headers: req.headers || {},
    params: req.params || {},
    query: req.query || {},
    body: req.body || {}
  }
}

/**
 * custom res object
 * @private
 */
function resObj (res) {
  var obj = {
    statusCode: res.statusCode
  }
  if (res.body) {
    obj.body = Object.assign({}, res.body)
    if (res.statusCode >= 400 && obj.body.stack) {
      var stackArr = obj.body.stack.split('\n    ')
      obj.body.stack = stackArr[0]
        + stackArr[1]
        + ' <...>'
    }
  }
  return obj
}

/**
 * log object
 * @private
 */
function logObj (type, status, obj) {
  consola.log(coloredSign(status)
    + ' '
    + type
    + ': '
    + util.inspect(obj, {
      colors: true,
      compact: false
    })
  )
}

/**
 * log error
 * @private
 */
function logError (res) {
  var status = res.statusCode / 100 | 0

  if (status < 4) {
    return
  }

  var body = res.body 
    ? res.body
    : res.statusMessage

  if (status === 4) {
    consola.warn(body)
  } else if (status === 5) {
    consola.error(body)
  }
}

/**
 * log error
 * @private
 */
function logRequest (req, res) {
  consola.log(coloredRequest(res.statusCode, req.httpVersion)
    + ' '
    + coloredMethod(req.method)
    + ' '
    + req.originalUrl
    + ' - '
    + coloredStatus(res.statusCode)
    + ' - '
    + res.responseTime
    + ' ms'
  )
}

/**
 * get colored sign
 * @private
 */
function coloredSign (status) {
  return ({
    2: '\x1b[92m',
    3: '\x1b[94m',
    4: '\x1b[93m',
    5: '\x1b[91m'
  }[status / 100 | 0] || '\x1b[39m')
  + '\x1b[1m'
  + '✔'
  + '\x1b[0m'
}

/**
 * get colored method
 * @private
 */
function coloredMethod (method) {
  return ({
    get: '\x1b[32m',
    head: '\x1b[32m',
    post: '\x1b[33m',
    put: '\x1b[34m',
    delete: '\x1b[31m',
    connect: '\x1b[39m',
    options: '\x1b[36m',
    trace: '\x1b[39m',
    patch: '\x1b[34m'
  }[method.toLowerCase()] || '\x1b[39m')
  + method
  + '\x1b[0m'
}

/**
 * get http version with background color
 * @private
 */
function coloredRequest (status, httpVersion) {
  return ({
    2: '\x1b[42m',
    3: '\x1b[44m',
    4: '\x1b[43m',
    5: '\x1b[41m'
  }[status / 100 | 0] || '\x1b[49m')
  + '\x1b[30m HTTP/'
  + httpVersion
  + ' '
  + '\x1b[0m'
}

/**
 * get colored status
 * @private
 */
function coloredStatus (status) {
  return ({
    2: '\x1b[32m',
    3: '\x1b[34m',
    4: '\x1b[33m',
    5: '\x1b[31m'
  }[status / 100 | 0] || '\x1b[39m')
  + status
  + '\x1b[0m'
}

module.exports = function () {
  return logger
}