Description
本文针对目前最新的log4js 2.x系列
2.x内置了对cluster的支持(不必写任何代码), 并且作者说2.x的性能更好(特别是file appender).
安装
npm install log4js --save
输出
[2017-09-17 12:56:44.378] [INFO] startup - Listening on port 3000
[2017-09-17 12:56:49.029] [INFO] console - This is from console.log
[2017-09-17 12:56:49.339] [WARN] http - GET /admin/import
第一行是通过logger.info打印出来的, 第二行是console.log, 第三行是expresss.js内部打出来的access log. 稍后将解释怎么处理这三种日志.
最小用法
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.level = 'debug'; // default level is OFF - which means no logs at all.
logger.debug("Some debug messages");
两种Configure方式
我喜欢第二种, 就像java中的log4j有log4j.xml或log4j.properties.
// 方式一
log4js.configure({
appenders: { console: { type: 'console' } },
categories: { default: { appenders: [ 'console' ], level: 'info' } }
});
// 方式二
log4js.configure('./config/log4js.json');
最小配置
见: Console Appender, 作者不推荐使用console, (因为它的内部实现全部是用console.log的形式输出的), 推荐使用stdout, 性能更好.
如果用stdout, 如下:
log4js.configure({
appenders: { 'out': { type: 'stdout' } },
categories: { default: { appenders: ['out'], level: 'info' } }
});
中等配置
{
"appenders": {
"console": { "type": "console" },
"cheeseLogs": { "type": "file", "filename": "logs/cheese.log" },
"no-debugs": { "type": "logLevelFilter", "appender":"cheeseLogs", "level": "info"}
},
"categories": {
"cheese": { "appenders": ["cheeseLogs"], "level": "info" },
"another": { "appenders": ["console"], "level": "debug" },
"default": { "appenders": ["console", "no-debugs"], "level": "debug"}
}
}
以中等配置为例, 理解一下最前面输出中的startup, console, http都是些什么. (这些都是日志的category), 那么在log4j.json中定义的是cheese, another, default这三种啊. (哦, log4js.getLogger("startup");这个参数传什么名字, 日志中就打印出来什么), 如果传的category在log4j.json中没有定义, 就会用default那个categories对应的配置. (明白了)
另外在categories中定义了每类日志的输出 level, 小于这个level的日志将不予处理.
在appenders中也可以定义level, 但是只有type为logLevelFilter的appender才能定义level.
并且logLevelFilter类型的appender只能基于某个已存在的appender.
以上中等配置中. 如果项目中用console.debug('this is some debug message');
, 那么这句话只会出现在控制台, 并不会出现在日志文件中. (这是因为虽然总体的输出level为debug, 所以console类型的appender会打印出这句话, 但是no-debugs
(名字乱取的)这个类型的appender限制了该类型的appender只输出info级别的日志)
startup
在./bin/www中, 有如下代码
/**
* Initialise log4js first, so we don't miss any log messages
*/
const log4js = require('log4js');
log4js.configure('./config/log4js.json');
const log = log4js.getLogger("startup");
log.info("Listing on port 3000");
其中log4js.getLogger(CATEGORY_NAME);
这是新建一个logger的实例, 会自动去找配置中categories中同名的category, 如果找不到就用default那个category, 比如这里的startup并不存在, 所以实际用的default
category.
自动处理console.log/console.error等
项目中大家都习惯了用console.log来记录日志 , 如何不更改已有的代码, 让log4js自动接手console.log?
作者在FAQ中有回答这个问题.
/**
* Initialise log4js first, so we don't miss any log messages
*/
const log4js = require('log4js');
log4js.configure('./config/log4js.json');
const log = log4js.getLogger("startup");
// see https://nomiddlename.github.io/log4js-node/faq.html
const consoleLogger = log4js.getLogger('console');
console.debug = consoleLogger.debug.bind(consoleLogger);
console.log = consoleLogger.info.bind(consoleLogger);
console.error = consoleLogger.error.bind(consoleLogger);
如何处理express.js自带的access log
这次从./bin/www转移到app.js中来.
var log4js = require('log4js');
var express = require('express');
//We won't need this.
//var logger = require('morgan');
var log = log4js.getLogger("app");
// replace this with the log4js connect-logger
// app.use(logger('dev'));
app.use(log4js.connectLogger(log4js.getLogger("http"), {level: 'auto', format: ':method :url', nolog: '\\.js|\\.css|\\.png'}));
看代码中的注释, 我们可以用npm uninstall morgan --save
卸载掉express generator包含的morgan组件. 因为在以上的代码中我们用log4js(而非morgan)接管了connect-logger.
auto, format及nolog的含义见: Connect / Express Logger
cyper实战
经过权衡, 我暂时配置了如下这款, 除了一点: 不知道怎么去掉时间的毫秒数, 查了文档, 对%d没有像log4j那样提供更精细的控制, 其它都足够满意.
{
"appenders": {
"stdout": {
"type": "stdout",
"layout": {
"type": "pattern",
"pattern": "[%d %p] %m"
}
},
"daily": {
"type": "dateFile",
"filename": "logs/app",
"pattern": ".yyyy-MM-dd.log",
"alwaysIncludePattern": true,
"compress": true,
"daysToKeep": 30,
"layout": {
"type": "pattern",
"pattern": "[%d %p] %m"
}
},
"file": {
"type": "file",
"filename": "logs/error.log",
"maxLogSize": 10485760,
"backups": 3,
"compress": true
},
"error": {
"type": "logLevelFilter",
"appender": "file",
"level": "error"
}
},
"categories": {
"default": {
"appenders": [
"stdout",
"daily",
"error"
],
"level": "info"
}
}
}
同时, 我会在开发模式下, 把日志级别动态调整为debug, 在./bin/www中还添加了如下代码:
/**
* Initialise log4js first, so we don't miss any log messages
*/
const log4js = require('log4js');
log4js.configure('./config/log4js.json');
const logger = log4js.getLogger("startup");
const consoleLogger = log4js.getLogger('console');
console.debug = consoleLogger.debug.bind(consoleLogger);
console.log = consoleLogger.info.bind(consoleLogger);
console.error = consoleLogger.error.bind(consoleLogger);
logger.info('env=', app.get('env'));
if(app.get('env') === 'development') {
logger.level = 'debug';
consoleLogger.level = 'debug';
}
会打印出如下格式的日志:
[2017-09-18 00:32:33.578 INFO] env= development
[2017-09-18 00:32:33.584 INFO] Listening on port 3000