這可能是外刊君推出的 Node.js 系列教程的第一篇。
log4js 是 Node.js 日誌處理中的數一數二的模組。比起console
或者 TJ 的 debug 有其優勢,尤其針對投入生產的 Node.js 專案來說下面這些是不可少的:
- 日誌分級
- 日誌分類
- 日誌落盤
本文將會給你一個 log4js 的全面介紹,讓你可以在專案中駕輕就熟的使用 log4js,開發除錯容易,線上更好地監控或排查問題。
牛刀小試
下面這三行程式碼為你展示了 log4js 最簡單的用法:
// file: simplest.js
var log4js = require(`log4js`);
var logger = log4js.getLogger();
logger.debug("Time:", new Date());複製程式碼
呼叫 .getLogger()
可以獲得 log4js 的 Logger
例項,這個例項的用法與 console
是一致的,可以呼叫.debug
(也有 .info
、.error
等方法)來輸出日誌。
執行 node simplest.js
,輸出如下:
$node simplest.js
[2016-08-21 00:01:24.852] [DEBUG] [default] - Time: 2016-08-20T16:01:24.852Z複製程式碼
Time: 2016-08-20T16:01:24.852Z
是我們想要輸出的內容,前面的包含說明符 [2016-08-21 00:01:24.852] [DEBUG] [default]
後文再表。
使用起來是不是也很簡單,好了,在我們深入到 log4js 高階用法之前,我們先來熟悉一下幾個 log4js 中的概念。
Level
這個理解起來不難,就是日誌的分級。日誌有了分級,log4js 才能更好地為我們展示日誌(不同級別的日誌在控制檯中採用不同的顏色,比如 error
通常是紅色的),在生產可以有選擇的落盤日誌,比如避免一些屬於.debug
才用的敏感資訊被洩露出來。
log4js 的日誌分為九個等級,各個級別的名字和權重如下:
{
ALL: new Level(Number.MIN_VALUE, "ALL"),
TRACE: new Level(5000, "TRACE"),
DEBUG: new Level(10000, "DEBUG"),
INFO: new Level(20000, "INFO"),
WARN: new Level(30000, "WARN"),
ERROR: new Level(40000, "ERROR"),
FATAL: new Level(50000, "FATAL"),
MARK: new Level(9007199254740992, "MARK"), // 2^53
OFF: new Level(Number.MAX_VALUE, "OFF")
}複製程式碼
上個圖:
ALL OFF
這兩個等級並不會直接在業務程式碼中使用。剩下的七個即分別對應 Logger
例項的七個方法,.trace .debug .info ...
。也就是說,你在呼叫這些方法的時候,就相當於為這些日誌定了級。因此,之前的 [2016-08-21 00:01:24.852] [DEBUG] [default] - Time: 2016-08-20T16:01:24.852Z
中的 DEBUG
既是這條日誌的級別。
型別
log4js 還有一個概念就是 category(型別),你可以設定一個 Logger
例項的型別,按照另外一個維度來區分日誌:
// file: set-catetory.js
var log4js = require(`log4js`);
var logger = log4js.getLogger(`example`);
logger.debug("Time:", new Date());複製程式碼
在通過 getLogger
獲取 Logger
例項時,唯一可以傳的一個引數就是 loggerCategory(如 `example`
),通過這個引數來指定 Logger
例項屬於哪個類別。這與 TJ 的 debug 是一樣的:
var debug = require(`debug`)(`worker`);
setInterval(function(){
debug(`doing some work`);
}, 1000);複製程式碼
在 debug 中 `worker`
,同樣也是為日誌分類。好了,回來執行 node set-catetory.js
:
[2016-08-21 01:16:00.212] [DEBUG] example - Time: 2016-08-20T17:16:00.212Z複製程式碼
與之前的 [2016-08-21 00:01:24.852] [DEBUG] [default] - Time: 2016-08-20T16:01:24.852Z
唯一不同的地方就在於,[default]
變成了 example
。
那類別有什麼用呢,它比級別更為靈活,為日誌了提供了第二個區分的維度,例如,你可以為每個檔案設定不同的 category,比如在 set-catetory.js 中:
// file: set-catetory.js
var log4js = require(`log4js`);
var logger = log4js.getLogger(`set-catetory.js`);
logger.debug("Time:", new Date());複製程式碼
就可以從日誌 [2016-08-21 01:24:07.332] [DEBUG] set-catetory.js - Time: 2016-08-20T17:24:07.331Z
看出,這條日誌來自於 set-catetory.js
檔案。又或者針對不同的 node package 使用不同的 category,這樣可以區分日誌來源於哪個模組。
Appender
好了,現在日誌有了級別和類別,解決了日誌在入口處定級和分類問題,而在 log4js 中,日誌的出口問題(即日誌輸出到哪裡)就由 Appender 來解決。
預設 appender
下面是 log4js 內部預設的 appender 設定:
// log4js.js
defaultConfig = {
appenders: [{
type: "console"
}]
}複製程式碼
可以看到,在沒有對 log4js 進行任何配置的時候,預設將日誌都輸出到了控制檯。
設定自己的 appender
我們可以通過log4js.configure
來設定我們想要的 appender。
// file: custom-appender.js
var log4js = require(`log4js`);
log4js.configure({
appenders: [{
type: `file`,
filename: `default.log`
}]
})
var logger = log4js.getLogger(`custom-appender`);
logger.debug("Time:", new Date());複製程式碼
在上例中,我們將日誌輸出到了檔案中,執行程式碼,log4js 在當前目錄建立了一個名為 default.log
檔案,[2016-08-21 08:43:21.272] [DEBUG] custom-appender - Time: 2016-08-21T00:43:21.272Z
輸出到了該檔案中。
log4js 提供的 appender
Console 和 File 都是 log4js 提供的 appender,除此之外還有:
- DateFile:日誌輸出到檔案,日誌檔案可以安特定的日期模式滾動,例如今天輸出到
default-2016-08-21.log
,明天輸出到default-2016-08-22.log
; - SMTP:輸出日誌到郵件;
- Mailgun:通過 Mailgun API 輸出日誌到 Mailgun;
- levelFilter 可以通過 level 過濾;
- 等等其他一些 appender,到這裡可以看到全部的列表。
過濾級別和類別
我們可以調整 appender 的配置,對日誌的級別和類別進行過濾:
// file: level-and-category.js
var log4js = require(`log4js`);
log4js.configure({
appenders: [{
type: `logLevelFilter`,
level: `DEBUG`,
category: `category1`,
appender: {
type: `file`,
filename: `default.log`
}
}]
})
var logger1 = log4js.getLogger(`category1`);
var logger2 = log4js.getLogger(`category2`);
logger1.debug("Time:", new Date());
logger1.trace("Time:", new Date());
logger2.debug("Time:", new Date());複製程式碼
執行,在 default.log
中增加了一條日誌:
[2016-08-21 10:08:21.630] [DEBUG] category1 - Time: 2016-08-21T02:08:21.629Z複製程式碼
來看一下程式碼:
- 使用
logLevelFilter
和level
來對日誌的級別進行過濾,所有權重大於或者等於DEBUG
的日誌將會輸出。這也是之前提到的日誌級別權重的意義; - 通過
category
來選擇要輸出日誌的類別,category2
下面的日誌被過濾掉了,該配置也接受一個陣列,例如[`category1`, `category2`]
,這樣配置兩個類別的日誌都將輸出到檔案中。
Layout
Layout 是 log4js 提供的高階功能,通過 layout 我們可以自定義每一條輸出日誌的格式。log4js 內建了四中型別的格式:
- messagePassThrough:僅僅輸出日誌的內容;
- basic:在日誌的內容前面會加上時間、日誌的級別和類別,通常日誌的預設 layout;
- colored/coloured:在 basic 的基礎上給日誌加上顏色,appender Console 預設使用的就是這個 layout;
- pattern:這是一種特殊型別,可以通過它來定義任何你想要的格式。
一個 pattern
的例子:
// file: layout-pattern.js
var log4js = require(`log4js`);
log4js.configure({
appenders: [{
type: `console`,
layout: {
type: `pattern`,
pattern: `[%r] [%[%5.5p%]] - %m%n`
}
}]
})
var logger = log4js.getLogger(`layout-pattern`);
logger.debug("Time:", new Date());複製程式碼
%r %p $m $n
是 log4js 內建的包含說明符,可以藉此來輸出一些 meta 的資訊,更多細節,可以參考 log4js 的文件。
一張圖再來說明一下,Logger、Appender 和 Layout 的定位。
實戰:輸出 Node 應用的 ACCESS 日誌 access.log
為了方便查問題,在生產環境中往往會記錄應用請求進出的日誌。那使用 log4js 怎麼實現呢,直接上程式碼:
// file: server.js
var log4js = require(`log4js`);
var express = require(`express`);
log4js.configure({
appenders: [{
type: `DateFile`,
filename: `access.log`,
pattern: `-yyyy-MM-dd.log`,
alwaysIncludePattern: true,
category: `access`
}]
});
var app = express();
app.use(log4js.connectLogger(log4js.getLogger(`access`), { level: log4js.levels.INFO }));
app.get(`/`, function(req,res) {
res.send(`前端外刊評論`);
});
app.listen(5000);複製程式碼
看看我們做了哪些事情:
- 配置了一個 appender,從日誌中選出類別為
access
的日誌,輸出到一個滾動的檔案中; log4js.getLogger(`access`)
獲取一個類別為access
的 Logger 例項,傳遞給log4js.connectLogger
中介軟體,這個中介軟體收集訪問資訊,通過這個例項打出。
啟動伺服器,訪問 http://localhost:5000,你會發現目錄中多了一個名為 access.log-2016-08-21.log
的檔案,裡面有兩條日誌:
[2016-08-21 14:34:04.752] [INFO] access - ::1 - - "GET / HTTP/1.1" 200 18 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
[2016-08-21 14:34:05.002] [INFO] access - ::1 - - "GET /favicon.ico HTTP/1.1" 404 24 "http://localhost:5000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"複製程式碼
通過 log4js 日誌的分類和appender功能,我們把訪問日誌輸出到了一個滾動更新的檔案之中。
總結
本文為大家全面地介紹了 log4js 的用法,與 console
或者簡單的日誌工具相比,log4js 使用起來更復雜,當然功能更強大,適合生產級應用的使用。如果大家有興趣的話,請留言告訴外刊君,接下來可能為大家介紹如何在 Node 應用中做配置管理。