原文地址:Comparing Winston and Bunyan Node.js Logging
如果你正在編寫一些生存周期比較長的應(yīng)用程序,詳細(xì)的日志記錄對于發(fā)現(xiàn)問題和調(diào)試代碼來說非常重要。沒有日志,你無法得知你的應(yīng)用正在做什么,有沒有發(fā)生錯誤,應(yīng)用已經(jīng)完成了預(yù)期的工作還是在你看不見的地方偷懶。
要求
我們先列出一些要求來確定選用哪個框架:
- 每個日志行都應(yīng)該有一個時間戳。這很好解釋——你應(yīng)該能夠從日志中得知每個動作發(fā)生的時間。
- 日志格式應(yīng)當(dāng)很容易被人和機器解讀。
- 允許多個可配置的目標(biāo)流。例如,你可能會將跟蹤日志寫入一個文件,而當(dāng)有錯誤發(fā)生時,將錯誤信息寫入同一個文件和錯誤日志文件,并且第一時間使用郵件將錯誤信息發(fā)送出去。
基于這些要求,有兩個Node.js的日志庫值得一試:
- 由
Trent Mick開發(fā)的Bunyan - 作為
Flatiron.js的一部分并由nodejitstu贊助的Winston
控制臺
在我們開始介紹Winston之前,先讓我們回顧一下我們的老朋友控制臺。你使用得最多的打印日志的方式可能是console.log()和console.error()。這比什么都不做要好,但并不是最好的解決方案。控制臺將以上信息分別寫入標(biāo)準(zhǔn)輸出stdout和標(biāo)準(zhǔn)錯誤stderr中。
當(dāng)目標(biāo)是終端或文件時,控制臺函數(shù)是同步的(避免丟失提早退出應(yīng)用程序的信息),而當(dāng)目標(biāo)是管道時,它們是異步的(避免長時間阻塞)。
也就是說,在下面的例子中,stdout是非阻塞的,而stderr則是阻塞的:
$ nodescript.js2>error.log | teeinfo.log
這種方式依賴于個人進(jìn)行配置和管理每一件事情,既耗時又容易出錯。你可能想要專注于你的應(yīng)用程序功能而不是這些瑣事??紤]到有持續(xù)維護(hù)并且開源的日志庫,如果你希望將注意力集中在開發(fā)功能上,大可不必在這上面消耗精力。
Winston
Winston是Node.js上最流行的日志庫之一。它被設(shè)計為一個簡單通用的日志庫,支持多種傳輸(一種傳輸實際上就是一種存儲設(shè)備,例如日志存儲在哪里)。Winston中的每一個logger實例在不同的日志級別可以存在多個傳輸配置。
安裝
npm install winston
使用
Winston最基本的使用方法就是導(dǎo)入Winston模塊后使用默認(rèn)實例。
var winston = require('winston');
winston.log('info', 'Hello distributed log files!');
winston.info('Hello again distributed logs');
相當(dāng)于:
var winston = require('winston');
var logger = new winston.Logger();
logger.log('info', 'Hello distributed log files!');
logger.info('Hello again distributed logs');
上面兩個例子都會產(chǎn)生以下輸出:
info: Hello distributed log files!
info: Hello again distributed logs
格式化
我個人對默認(rèn)格式化程序的缺乏細(xì)節(jié)有點小疑惑。沒有時間戳、機器名或進(jìn)程ID,而且輸出格式并不適合機器分析。話雖如此,你可以通過增加一點額外的工作量來得到所有的信息。
winston.info('Hello world!', {timestamp: Date.now(), pid: process.pid});
執(zhí)行上面語句會得到以下信息更為豐富的輸出結(jié)果,但仍然不是非常適合機器進(jìn)行分析。
info: Hello world! timestamp=1402286804314, pid=80481
最后,日志方法提供了相同的字符串插值方法util.format,例如:
winston.log('info', 'test message %d', 123);
Transporters
Winston可以通過構(gòu)造函數(shù)或項目的Github頁面上詳細(xì)介紹的接口來進(jìn)行配置。大部分配置項都圍繞著傳輸。開箱即用的Winston配備了console對象和基于文件的傳輸,如果你打開npmjs.org的話會發(fā)現(xiàn),從MongoDB到第三方社區(qū)平臺,一切你能想到的模塊都有。
在我看來最值得關(guān)注的transporters之一是Nathan Zadoks開發(fā)的winstron-irc,可以用于向團(tuán)隊的IRC頻道記錄錯誤日志,我覺得這非常方便。
winston.add(require('winston-irc'), {
host: 'irc.somewhere.net',
nick: 'logger',
pass: 'hunter2',
channels: {
'#logs': true,
'sysadmin': ['warn', 'error']
}
});
多個記錄器
一旦你的應(yīng)用開始增長,你可能會希望有多個不同配置的記錄器,每個記錄器負(fù)責(zé)不同的功能區(qū)。Winston有兩種方式支持以上做法:通過winston.loggers或者winston.Container的實例。事實上,winston.loggers只是一個預(yù)定義的winston.Container實例。
winston.loggers.add('category1', {console: {...}, file: {...}});
winston.loggers.add('category2', {irc: {...}, file: {...}});
既然你的記錄器已經(jīng)配置好了,你可以在任意文件中引入Winston并訪問這些預(yù)配置的記錄器:
var category1 = winston.loggers.get('category1');
category1.info('logging from your IoC container-based logger');
更多
以上是最基本的Winston使用方法,它還有一些其他的功能,其中最值得注意的是: