问题:项目中用log4js
可以正常写入日志到文件中,后来使用pm2
启动后,发现文件不能写入到文件了。网上查了很久,并没有找到原因,所以就想到了查看源码的方法,来查找到底是哪里出了问题。
先看相关的配置
log4js
配置:
1 2 3 4 5 6 7
| { "type": "dateFile", "filename": "logfile/", "pattern": "flow-yyyy-MM-dd-hh.log", "alwaysIncludePattern": true, "layout": { "type": "messagePassThrough" } }
|
pm2
配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| { "apps": [ { "name": "project_name", "script": "index.js", "exec_mode": "cluster", "instances": 4, "instance_var": "INSTANCE_ID", "max_memory_restart": "1G", "autorestart": true, "node_args": [], "watch": ["config", "data", "lib","public", "index.js"], "watch_options": { "usePolling": true }, "args": [], "env": {}, "env_dev": { ... }, "env_production": { ... } } ] }
|
log4js
无法自动生成对应时间格式的文件
正常直接启动会在配置log目录下生成一个flow-yyyy-MM-dd-hh.log
格式的文件,但是用pm2
启动的时候并没有生成。
log4js的调用方法为require('log4js').getLogger()
,所以就直接在源码中找getLogger
:
1、通过package.json
中的main
我们确定它的主入口文件为./lib/log4js
;
2、找到getLogger
方法
1 2 3 4 5 6 7 8 9 10 11
| function getLogger(category) { const cat = category || 'default'; debug(`creating logger as ${isMaster() ? 'master' : 'worker'}`); return new Logger((isMaster() ? sendLogEventToAppender : workerDispatch), cat); }
|
其中有个isMaster()
方法,判断是否为主进程
1 2 3 4 5 6 7
| function isPM2Master() { return config.pm2 && process.env[config.pm2InstanceVar] === '0'; } function isMaster() { return config.disableClustering || cluster.isMaster || isPM2Master(); }
|
可以看到isPM2Master
是通过config中的pm2
参数和pm2InstanceVar
来确定的。
所以我们需要在log4js
的配置中增加这两个配置。
1 2 3 4
| { pm2: true, pm2InstanceVar: "INSTANCE_ID" // 与pm2的配置对应 }
|
pm2 中NODE_APP_INSTANCE 特定的环境变量可以用来判断主从进程
此时重启pm2
后(需要pm2 delete
不然pm2配置文件不生效),已经可以看到生成的文件了,但是日志还是不能写入。
接着看源码:
workerDispatch
方法
1 2 3 4
| function workerDispatch(logEvent) { debug(`sending message to master from worker ${process.pid}`); process.send({ topic: 'log4js:message', data: serialise(logEvent) }); }
|
此方法为工作进程接收到log事件,并发出消息,必定有接收的地方,通过查找代码发现此方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function configure(configurationFileOrObject) { if (config.disableClustering) { debug('Not listening for cluster messages, because clustering disabled.'); } else { if (isPM2Master()) { debug('listening for PM2 broadcast messages'); process.removeListener('message', receiver); process.on('message', receiver); } else if (cluster.isMaster) { debug('listening for cluster messages'); cluster.removeListener('message', receiver); cluster.on('message', receiver); } else { debug('not listening for messages, because we are not a master process'); } }
|
我们可以看到在if
条件中有监听的操作,但是,后面的监听函数没有执行,后来才注意到里面的三行注释,需要安装pm2-intercom
;在执行了pm2 install pm2-intercom
后,果然可以了,日志成功写入到了文件中。