问题:项目中用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后,果然可以了,日志成功写入到了文件中。