winston日志框架使用
原來一直是使用log4js
做日志輸出爹谭,原來只是輸出到標準輸出中枷邪,用了3年了,一直沒換過∨捣玻現(xiàn)在為了將詳細的日志都記錄下來东揣,不光輸出到標準出,而且根據(jù)服務的分層輸出到不同的文件中腹泌。如:全部的log都輸出到debug文件及標準輸出中嘶卧,service層的log輸出service.log文件中,dao層的log輸出到dao.log文件中凉袱,為了防止log文件過大芥吟,需按日期切分,如:按天专甩。
為何選擇winston
- github start數(shù)多钟鸵,夠直接把。
- 更加靈活涤躲,可以靈活的組織transport棺耍,來完成比較復雜的日志輸出任務。
- 日志格式為json字符串种樱,方便后期分析蒙袍,當然可以自定義format.
- 支持簡單的log分析,Profiling缸托。
- 支持stream Api左敌。
- 簡單Log Query Api,當然無法和專業(yè)的日志分析工具比俐镐。
我要達到的效果
- 按天生成日志文件矫限。
- 根據(jù)不同的代碼分層來產(chǎn)生不同的log輸出到不同的文件。
- 所有分層產(chǎn)生的log不光輸出到log文件還要輸出到標準輸出佩抹。
- 自定義格式化日志輸出叼风,輸出到標準輸出的格式便于讀取,輸出到log文件的格式便于分析棍苹。
- 可以捕獲系統(tǒng)崩潰異常无宿。
日志輸出方法
整合多個transport及封裝
格式化輸出到標準輸出的日志格式。
格式為
[2017-09-21 23:41:05.122] [DEBUG] - 輸出日志的module 日志詳細信息
但是在winston中沒有可以像log4js
一樣可以定義category
枢里,為了達到這個效果孽鸡,我們利用winston的 meta
特性來實現(xiàn)這一功能蹂午。winston中log
方法輸出的最后一個參數(shù)為對象的話,會被解析成 meta
彬碱,我們在meta
中自定義一個
module
字段來標記日志來自哪個模塊豆胸。
const myLogFormatter = function (options) {
const timestamp = options.timestamp();
const level = options.level.toUpperCase();
const message = options.message || '';
let module = 'default';
// meta中module,標記日志來自哪個模塊
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)建標準輸出的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模塊專用輸出到文件的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模塊專用輸出到文件的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
});
為各個container
添加transport
嚼沿。
// default container輸出日志到標準輸出及debug.log文件中
winston.loggers.add('default', {
transports: [
transportConsole,
debugTransportFile
],
});
// service container輸出日志到標準輸出估盘、debug.log及service.log文件中
winston.loggers.add('service', {
transports: [
transportConsole,
serviceTransportFile,
debugTransportFile
],
});
// dao container輸出日志到標準輸出、debug.log及dao.log文件中
winston.loggers.add('dao', {
transports: [
transportConsole,
daoTransportFile,
debugTransportFile
],
});
代理各個container
的debug
骡尽、info
等方法遣妥,達到可以顯示日志來自哪個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
中打印日志“登錄成功”燥透,日志級別為info
。
getServiceLogger('userService').info('登錄成功');
控制臺輸出為:
[2017-09-22 00:09:45.026] [INFO] userService - 登錄成功
此日志會輸出在標準輸出中辨图、debug.log中及service.log中班套,日志中寫入的控制臺輸出的略有不同。
寫入的日志格式為:
{"module":"userService","level":"info","message":"登錄成功","timestamp":"2017-09-21T16:01:45.026Z"}
更多功能
我寫了幾個demo故河,包括基本使用吱韭,多個輸出源,捕獲系統(tǒng)崩潰錯誤鱼的,按天生成日志文件理盆。代碼地址為: