node.js debug模組淺析及改進

Shawn-ye發表於2017-07-03

debug模組簡介

debug模組是node.js上比較流行的一個開源日誌工具。
使用如下程式碼即可安裝:

$ npm install debug

在需要使用的檔案裡新增如下程式碼即可使用:

const testDebugger = require("debug")("log");
testDebugger("this is test");

再用node執行該檔案,即可在控制檯上獲得如下一條類似於下面的輸出:

Fri, 30 Jun 2017 02:26:02 GMT log this is test

記得要在node命令前加上DEBUG=”log”,不然是看不見這條日誌的。

原始碼簡單分析

namespace

const testDebugger = require("debug")("log");
testDebugger("this is test");

namespace是debug模組用來區分每一條日誌的來源的東西,如例子中的log。它緊跟著時間戳出現在日誌中,告訴使用者這條日誌的來源。
如上面的程式碼,呼叫testDebugger函式所產生的所有日誌都將繫結在log這個namespace下。
為什麼要折騰這麼一個namespace呢?是為了方便在不同的環境下,選擇哪些日誌可以輸出。指定namespace的命令,就是前文中的DEBUG="log"。這裡就指定了只有log這個namespace下的日誌會被輸出。再寬泛一點,可以使用萬用字元DEBUG="*"來選擇輸出所有日誌。

createDebug

在debug.js中可以找到這樣的一行程式碼

exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;

它將createDebug方法暴露出來。即,當你require("debug")時,獲得的就是createDebug函式。
createDebug函式裡主要做了一件事情,就是在函式內部建立了一個名為debug的函式,並將其返回。其實就是高階函式。
這個debug函式的程式碼不長,幾十行,主要做了以下幾件事情:

  • 計算時間偏移量
  • 處理輸入引數並對其進行格式化。和console.log()一樣,debug模組建立出的日誌函式同樣支援格式處理符號,如%s %d %c等。
  • 初始化這個日誌函式,繫結相關的資訊。主要是兩個,一個是namespace的繫結,一個是顏色的繫結。

formatArgs

這個函式是用來格式化引數的。程式碼如下

function formatArgs(args) {
  var name = this.namespace;
  var useColors = this.useColors;

  if (useColors) {
    var c = this.color;
    var prefix = '  \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';

    args[0] = prefix + args[0].split('\n').join('\n' + prefix);
    args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
  } else {
    args[0] = new Date().toUTCString()
      + ' ' + name + ' ' + args[0];
  }
}

首先是從this物件上拉取這條日誌的namespace和顏色資訊。
如果這個日誌被配置為彩色輸出,即this.useColors === true的,那麼就按照namespace + 日誌內容 + 時間偏移量的格式輸出。
否則就按照UTC絕對時間 + namespace + 日誌內容 輸出。

selectColor

function selectColor(namespace) {
  var hash = 0, i;

  for (i in namespace) {
    hash  = ((hash << 5) - hash) + namespace.charCodeAt(i);
    hash |= 0; // Convert to 32bit integer
  }

  return exports.colors[Math.abs(hash) % exports.colors.length];
}

由於ANSI color的格式大概是\u001b[31m這樣的,變化的部分只有數字31的最後一位。
作者將幾個顏色的末位數字儲存在了這個陣列裡:

exports.colors = [6, 2, 3, 4, 5, 1];

然後通過這個selectColor函式去對輸入字串(就是namespace)做一次雜湊,輸出一個1~6之間的數字,從而決定它的顏色。
同樣的字串的雜湊值是固定的,所以同一個namespace對應的顏色也是一樣的。
同時由於雜湊本身的特性,不同的namespace的顏色很可能是不一樣的。

debug模組的不足之處

debug模組在使用過程中,有如下幾點不能滿足應用需要。

  • namespace的設定不夠靈活,缺少日誌級別的功能。更多的時候需要指定LOG LEVEL而不是LOG NAME。
  • 開啟顏色選項以後,日誌的輸出格式變成了時間偏移量,顯得很奇怪.
  • 時間顯示格式為UTCString,可讀性很差且浪費磁碟空間

改進

  • createDebug函式的namespace用作日誌Level(DBG, MSG, WARN, ERR),併為每種級別的日誌分配相應的顏色。新增一個引數作為日誌來源提示。
  • 啟用日誌顏色時格式修改為和無顏色時一樣的格式
  • 時間顯示格式修改為年月日+時間

最後的log格式如下:

2017-07-03T08:27:41 ServiceName   [MSG]  HTTPS Listening on 0.0.0.0:8088

相關文章