開發一個項目時,能夠經過控制檯輸出或者debug來獲取到項目的運行信息。當項目上線時,咱們就須要經過日誌來分析。如同Java的log4j,nodejs中也有相關的log4js。使用過log4j的同窗應該對此不會陌生。node
log4js共有6種日誌級別,分別爲:trace、debug、info、warn、error、fatal。權值從小到大,其初始化代碼爲:git
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"),
假如設置默認的日誌級別爲info,那麼權值小於info的日誌不會被記錄下來,也就是說只有調用log.info(), log.warn(), log.error()或者log.fatal()纔會觸發記錄日誌。該部分代碼在lib/logger.js中。github
Logger.prototype.log = function() { var args = Array.prototype.slice.call(arguments) , logLevel = levels.toLevel(args.shift()) , loggingEvent; if (this.isLevelEnabled(logLevel)) { loggingEvent = new LoggingEvent(this.category, logLevel, args, this); this.emit("log", loggingEvent); } };
log4js能夠做爲express的一箇中間件來使用。首先須要引入log4jsexpress
var express = require("express"); var log4js = require("log4js"); var app = express();
接着配置log4jsjson
log4js.configure({ appenders: [ { type: 'console' }, { type: 'file', filename: 'cheese.log', category: 'cheese' } ] });
該配置的意思是console是默認的appender,使用cheese這個appender時會將日誌記錄文件中,日誌文件名爲cheese.log。app
而後用use鏈接到中間件,咱們默認使用的是cheese這個appender,級別爲info。ui
app.use(log4js.connectLogger(log4js.getLogger("cheese"), {level: log4js.levels.INFO}));
其輸出與此相似:this
[2014-07-04 20:27:21.205] [INFO] cheese - 127.0.0.1 - - "GET / HTTP/1.1" 200 22896 "" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"spa
......prototype
上面的作法是能夠的,只是當中間件太多的時候,都寫在同一個文件中也許感受會有些醜陋。因此我傾向於將其分離出來做爲單獨的一個模塊,也就是一個單獨的文件。而後對外暴露接口。
var path = require("path"); var log4js = require("log4js"); /** * 日誌配置 */ exports.configure = function() { log4js.configure(path.join(__dirname, "log4js.json")); } /** * 暴露到應用的日誌接口,調用該方法前必須確保已經configure過 * @param name 指定log4js配置文件中的category。依此找到對應的appender。 * 若是appender沒有寫上category,則爲默認的category。能夠有多個 * @returns {Logger} */ exports.logger = function(name) { var dateFileLog = log4js.getLogger(name); dateFileLog.setLevel(log4js.levels.INFO); return dateFileLog; } /** * 用於express中間件,調用該方法前必須確保已經configure過 * @returns {Function|*} */ exports.useLog = function() { return log4js.connectLogger(log4js.getLogger("app"), {level: log4js.levels.INFO}); }
log4js.json文件內容以下
{ "appenders": [ { "type": "console" }, { "type": "dateFile", "filename": "logs/booklist.log", "pattern": "-yyyy-MM-dd", "alwaysIncludePattern": true } ] }
配置很簡單,配置了兩個appender,一個是控制檯的,一個是dateFile,意思是天天都產生一個日誌文件。注意到我這裏並無配置category,這樣的話當沒有找到對應的appender時,這兩個appender就是默認的appender。有些時候明明感受配置沒有錯,可是日誌文件並無產生日誌,每每問題就出在這裏。
而後在app.js中咱們修改成以下
var express = require("express"); // 這個是咱們上面自定義的模塊 var log4js = require("./log"); var app = express(); app.configure(); app.use(log4js.useLog()); ...
好了,上面對於單進程是適用的,可是若是你的nodejs應用是多進程的,使用上面的配置你會看到日誌的輸出有點奇怪,好比:
感受有點像是資源搶佔了。
log4js的wiki中有給出multiprocess的配置。可是當時使用的時候也會有問題,當時沒有細究。不過社區中有人創建了另一種方式,我採用了這種。能夠參看一下這個issue。下面咱們來配置一下。修改咱們在上面修改的log模塊文件,變爲:
var path = require("path"); var log4js = require("log4js"); /** * 多進程的日誌配置 */ exports.configure = function(mode) { if (mode === "master") { log4js.configure(path.join(__dirname, "./log4js-master.json")); } else { // 多進程的配置項 log4js.configure(path.join(__dirname, "./log4js-worker.json")); // 單進程的配置項 // log4js.configure(path.join(__dirname, "../config/log4js.json")); } } /** * 暴露到應用的日誌接口,調用該方法前必須確保已經configure過 * @param name 指定log4js配置文件中的category。依此找到對應的appender。 * 若是appender沒有寫上category,則爲默認的category。能夠有多個 * @returns {Logger} */ exports.logger = function(name) { var dateFileLog = log4js.getLogger(name); dateFileLog.setLevel(log4js.levels.INFO); return dateFileLog; } /** * 用於express中間件,調用該方法前必須確保已經configure過 * @returns {Function|*} */ exports.useLog = function() { return log4js.connectLogger(log4js.getLogger("app"), {level: log4js.levels.INFO}); }
主要是修改了configure方法。
log4js-master.json的內容爲:
{ "appenders": [{ "type": "clustered", "appenders": [ { "type": "console" }, { "type": "dateFile", "filename": "logs/booklist.log", "pattern": "-yyyy-MM-dd", "alwaysIncludePattern": true, "pollInterval": 1, "category": "dateFileLog" } ] }] }
log4js-worker.js的內容爲:
{ "appenders": [{ "type": "clustered" }] }
假設主進程的內容在文件master.js,工做進程在worker.js。master.js中的配置內容爲:
var log4js = require("./lib/log"); log4js.configure("master");
worker.js的配置內容爲:
var express = require("express"); // 這個是咱們上面自定義的模塊 var log4js = require("./log"); var app = express(); app.configure("worker"); app.use(log4js.useLog()); ...
如此就完成了。
須要在某個地方記錄日誌的時候,咱們能夠如此
var log = require("./log").logger("index"); // logger中的參數隨便起
...
log.info("..."); log.error("...")
log4js還有挺多好玩的內容,好比smtp。這是個頗有用的功能,好比當項目發生某個錯誤時,你但願程序能發郵件通知你,該功能就能派出用場了。
另外,我開源了一個項目booklist。該項目主要在於探討nodejs創建應用所須要或者注意的地方,很是期待各位指導與探討,謝謝!