Проблема с записью журнала PM2 + Log4js в режиме кластера

Node.js задняя часть PM2

Эта статья была впервые опубликована в моем личном блогеБлог Сая
Пожалуйста, укажите источникalipot.top/blog/5 нет 45 нет 9…


Проблема: используется в проектеlog4jsЖурнал можно нормально записать в файл, а потом использоватьpm2После запуска обнаруживается, что запись в файл невозможна. Я долго искал в Интернете и не мог найти причину, поэтому я подумал о методе просмотра исходного кода, чтобы узнать, что пошло не так.

#Сначала посмотрите на соответствующую конфигурацию

log4jsКонфигурация:

{
    "type": "dateFile",
    "filename": "logfile/",
    "pattern": "flow-yyyy-MM-dd-hh.log",
    "alwaysIncludePattern": true,
    "layout": { "type": "messagePassThrough" }
}

pm2Конфигурация:

{
    "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Файл, соответствующий формату времени, не может быть сгенерирован автоматически

Обычный прямой запуск создаст журнал в каталоге журнала конфигурации.flow-yyyy-MM-dd-hh.logформатировать файл, но сpm2Он не генерируется при запуске.

Метод вызова log4js:require('log4js').getLogger(), так что вы можете найти его прямо в исходном кодеgetLogger:
1. Пройтиpackage.jsonсерединаmainМы определили, что его основной входной файл./lib/log4js;
2. найтиgetLoggerметод

/**
 * Get a logger instance.
 * @static
 * @param loggerCategoryName
 * @return {Logger} instance of logger for the category
 */
function getLogger(category) {
    const cat = category || 'default'
    debug(`creating logger as ${isMaster() ? 'master' : 'worker'}`)
    return new Logger(isMaster() ? sendLogEventToAppender : workerDispatch, cat)
}

один из нихisMaster()метод, чтобы определить, является ли это основным процессом

function isPM2Master() {
    return config.pm2 && process.env[config.pm2InstanceVar] === '0'
}

function isMaster() {
    return config.disableClustering || cluster.isMaster || isPM2Master()
}

можно увидетьisPM2Masterчерез конфигpm2параметры иpm2InstanceVarчтобы быть уверенным. Поэтому нам нужноlog4jsДобавьте эти две конфигурации в файл configuration.

{
    pm2: true,
    pm2InstanceVar: "INSTANCE_ID" // 与pm2的配置对应
}

pm2 в конкретной переменной среды NODE_APP_INSTANCEМожет использоваться для определения процесса master-slave

Перезагрузитесь в это времяpm2после (обязательноpm2 deleteВ противном случае конфигурационный файл pm2 не вступит в силу), вы уже видите сгенерированный файл, но лог все равно не записывается. Затем посмотрите исходный код:

# workerDispatchметод

function workerDispatch(logEvent) {
    debug(`sending message to master from worker ${process.pid}`)
    process.send({ topic: 'log4js:message', data: serialise(logEvent) })
}

Этот метод получает событие журнала для рабочего процесса и отправляет сообщение. Должно быть место для его получения. Найдите этот метод, просмотрев код:

function configure(configurationFileOrObject) {
  // ...
  if (config.disableClustering) {
    debug('Not listening for cluster messages, because clustering disabled.');
  } else {
    // PM2 cluster support
    // PM2 runs everything as workers - install pm2-intercom for this to work.
    // we only want one of the app instances to write logs
    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После этого, конечно же, журнал был успешно записан в файл.

TypeError The header content contains invalid characters