winston日志框架使用
原來(lái)一直是使用log4js做日志輸出,原來(lái)只是輸出到標(biāo)準(zhǔn)輸出中,用了3年了,一直沒(méi)換過(guò)?,F(xiàn)在為了將詳細(xì)的日志都記錄下來(lái),不光輸出到標(biāo)準(zhǔn)出,而且根據(jù)服務(wù)的分層輸出到不同的文件中。如:全部的log都輸出到debug文件及標(biāo)準(zhǔn)輸出中,service層的log輸出service.log文件中,dao層的log輸出到dao.log文件中,為了防止log文件過(guò)大,需按日期切分,如:按天。
為何選擇winston
- github start數(shù)多,夠直接把。
- 更加靈活,可以靈活的組織transport,來(lái)完成比較復(fù)雜的日志輸出任務(wù)。
- 日志格式為json字符串,方便后期分析,當(dāng)然可以自定義format.
- 支持簡(jiǎn)單的log分析,Profiling。
- 支持stream Api。
- 簡(jiǎn)單Log Query Api,當(dāng)然無(wú)法和專(zhuān)業(yè)的日志分析工具比。
我要達(dá)到的效果
- 按天生成日志文件。
- 根據(jù)不同的代碼分層來(lái)產(chǎn)生不同的log輸出到不同的文件。
- 所有分層產(chǎn)生的log不光輸出到log文件還要輸出到標(biāo)準(zhǔn)輸出。
- 自定義格式化日志輸出,輸出到標(biāo)準(zhǔn)輸出的格式便于讀取,輸出到log文件的格式便于分析。
- 可以捕獲系統(tǒng)崩潰異常。
日志輸出方法
整合多個(gè)transport及封裝
格式化輸出到標(biāo)準(zhǔn)輸出的日志格式。
格式為
[2017-09-21 23:41:05.122] [DEBUG] - 輸出日志的module 日志詳細(xì)信息
但是在winston中沒(méi)有可以像log4js一樣可以定義category,為了達(dá)到這個(gè)效果,我們利用winston的 meta 特性來(lái)實(shí)現(xiàn)這一功能。winston中log方法輸出的最后一個(gè)參數(shù)為對(duì)象的話(huà),會(huì)被解析成 meta,我們?cè)?code>meta中自定義一個(gè)
module字段來(lái)標(biāo)記日志來(lái)自哪個(gè)模塊。
const myLogFormatter = function (options) {
const timestamp = options.timestamp();
const level = options.level.toUpperCase();
const message = options.message || '';
let module = 'default';
// meta中module,標(biāo)記日志來(lái)自哪個(gè)模塊
if (options.meta && options.meta.module) {
module = options.meta.module;
}
const formatted = `[${timestamp}] [${level}] ${module} - `;
if (options.colorize) {
const colorStr = winston.config.colorize(options.level, formatted);
return `${colorStr}${message}`;
}
return `${formatted}${message}`;
};
創(chuàng)建標(biāo)準(zhǔn)輸出的transport
const transportConsole = new winston.transports.Console({
json: false,
prettyPrint:true,
colorize: true,
level:'debug',
timestamp: function () {
return moment().format('YYYY-MM-DD HH:MM:ss.SSS');
},
formatter: myLogFormatter,
});
創(chuàng)建所有日志輸出到文件的transport,日志輸出到debug.log
const debugTransportFile = new winston.transports.File({
name: 'full',
filename: __dirname + '/logs/debug.log',
json: true,
level:'debug',
maxsize: 1024 * 1024 * 10 // 10MB
});
service模塊專(zhuān)用輸出到文件的transport,日志輸出到service.log
const serviceTransportFile = new winston.transports.File({
name: 'service',
filename: __dirname + '/logs/service.log',
json: true,
level:'debug',
maxsize: 1024 * 1024 * 10 // 10MB
});
dao模塊專(zhuān)用輸出到文件的transport,日志輸出到dao.log
const daoTransportFile = new winston.transports.File({
name: 'dao',
filename: __dirname + '/logs/dao.log',
json: true,
level:'debug',
maxsize: 1024 * 1024 * 10 // 10MB
});
為各個(gè)container添加transport。
// default container輸出日志到標(biāo)準(zhǔn)輸出及debug.log文件中
winston.loggers.add('default', {
transports: [
transportConsole,
debugTransportFile
],
});
// service container輸出日志到標(biāo)準(zhǔn)輸出、debug.log及service.log文件中
winston.loggers.add('service', {
transports: [
transportConsole,
serviceTransportFile,
debugTransportFile
],
});
// dao container輸出日志到標(biāo)準(zhǔn)輸出、debug.log及dao.log文件中
winston.loggers.add('dao', {
transports: [
transportConsole,
daoTransportFile,
debugTransportFile
],
});
代理各個(gè)container的debug、info等方法,達(dá)到可以顯示日志來(lái)自哪個(gè)module的功能。
const defaultLog = winston.loggers.get('default');
const serviceLog = winston.loggers.get('service');
const daoLog = winston.loggers.get('dao');
// 封裝default
const getDefaultLogger = (module) => {
return {
debug: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
defaultLog.debug.apply(defaultLog, fullParams);
},
info: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
defaultLog.info.apply(defaultLog, fullParams);
},
warn: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
defaultLog.warn.apply(defaultLog, fullParams);
},
error: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
defaultLog.error.apply(defaultLog, fullParams);
}
};
};
// 封裝service
const getServiceLogger = (module) => {
return {
debug: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
serviceLog.debug.apply(serviceLog, fullParams);
},
info: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
serviceLog.info.apply(serviceLog, fullParams);
},
warn: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
serviceLog.warn.apply(serviceLog, fullParams);
},
error: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
serviceLog.error.apply(serviceLog, fullParams);
}
};
};
// 封裝dao
const getDaoLogger = (module) => {
return {
debug: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
daoLog.debug.apply(daoLog, fullParams);
},
info: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
daoLog.info.apply(daoLog, fullParams);
},
warn: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
daoLog.warn.apply(daoLog, fullParams);
},
error: (...args) => {
const meta = { module };
const fullParams = args.concat(meta);
daoLog.error.apply(daoLog, fullParams);
}
};
};
封裝后如何使用?
比如在我們代碼代碼的service層中的userService中打印日志“登錄成功”,日志級(jí)別為info。
getServiceLogger('userService').info('登錄成功');
控制臺(tái)輸出為:
[2017-09-22 00:09:45.026] [INFO] userService - 登錄成功
此日志會(huì)輸出在標(biāo)準(zhǔn)輸出中、debug.log中及service.log中,日志中寫(xiě)入的控制臺(tái)輸出的略有不同。
寫(xiě)入的日志格式為:
{"module":"userService","level":"info","message":"登錄成功","timestamp":"2017-09-21T16:01:45.026Z"}
更多功能
我寫(xiě)了幾個(gè)demo,包括基本使用,多個(gè)輸出源,捕獲系統(tǒng)崩潰錯(cuò)誤,按天生成日志文件。代碼地址為: