Winston: Ошибка записи в файл при вызове process.exit (0)

Созданный на 25 мар. 2013  ·  87Комментарии  ·  Источник: winstonjs/winston

Когда вы настроили Winston для входа в файл и вызываете process.exit (0) в своем коде, Winston никогда не заканчивает тем, что создает файл журнала и добавляет сообщения журнала в файл.

В идеальном мире winston с радостью справился бы с этим пограничным случаем и записал бы в файл, но я также был бы в порядке, если бы имел возможность вызвать сброс на экземпляре регистратора, чтобы вручную принудительно сбросить файл.

На данный момент может быть какой-то способ вручную `` очистить '', но он не задокументирован, и мне не повезло с ручным закрытием / завершением / уничтожением экземпляра регистратора или его внутренних потоков до сих пор таким образом, что фактически приводит к появлению журналов записывается в файл ..

var winston = require('winston');
var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)(),
    new (winston.transports.File)({ filename: 'winston.log' })
  ]
});

logger.info('info logged');
logger.error('error logged');

process.exit(0);
// the two logs get written out to console, but not to the winston.log file/
bug important winston-file

Самый полезный комментарий

@danielweck Нет, он сломан: # 1629 # 1504!

6 лет, это верно, 6 лет для ошибки с пометкой _important_. Это впечатляет на грани.

Все 87 Комментарий

В узле методы console. * Пишут асинхронно, транспорт файлов - асинхронный. Вы закрываете процесс еще до того, как узел записал данные.

В понедельник 25 марта 2013 года в 19:45 Юрий Запучлак написал:

Когда вы настроили Winston для входа в файл и вызываете process.exit (0) в своем коде, Winston никогда не заканчивает тем, что создает файл журнала и добавляет сообщения журнала в файл.
В идеальном мире winston с радостью справился бы с этим пограничным случаем и записал бы в файл, но я также был бы в порядке, если бы имел возможность вызвать сброс на экземпляре регистратора, чтобы вручную принудительно сбросить файл.
На данный момент может быть какой-то способ вручную `` очистить '', но он не задокументирован, и мне не повезло с ручным закрытием / завершением / уничтожением экземпляра регистратора или его внутренних потоков до сих пор таким образом, что фактически приводит к появлению журналов записывается в файл ..
var winston = require ('winston'); var logger = new (winston.Logger) ({транспорты: [новые (winston.transports.Console) (), новые (winston.transports.File) ({имя файла: 'winston.log'})]}); logger.info ('информация записана'); logger.error ('ошибка записана'); process.exit (0); // два журнала записываются на консоль, но не в файл winston.log /

-
Ответьте на это письмо напрямую или просмотрите его на GitHub (https://github.com/flatiron/winston/issues/228).

Хм. В этом случае, если нужно убить процесс узла, но нужно регистрировать информацию прямо перед тем, как они его уничтожат, помещает process.exit () внутри setTimeout () с достаточно большой продолжительностью времени - единственное, что можно сделать, чтобы гарантировать что Winston на самом деле записывает сообщения в файл журнала?

Для наглядности, console.log и друзья синхронны .

@yzapuchlak На самом деле я не тестировал, но я тоже этим занимаюсь.

@yzapuchlak setTimeout _

setTimeout 2000 или 5000 работает в моем простом тестовом сценарии, но не тогда, когда я пытаюсь использовать его в моем реальном коде. Итак, я не знаю, насколько надежным будет это потенциальное исправление. Я займусь этой проблемой позже, если мне не повезет с дополнительным фронтом обратного вызова.

@dtex Я просто попытался использовать необязательный обратный вызов (как показано в следующем примере кода), но это все еще не привело к записи журналов в файл. В этом случае файл фактически создается, но журналы в него не записываются.

var winston = require('winston');
var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)(),
    new (winston.transports.File)({ filename: 'winston.log' })
  ]
});

logger.info('winston - info logged');
logger.error('winston - error logged');

logger.info('winston - exiting now', { seriously: true }, function(err, level, msg, meta) {
  console.log('console - CALLING PROCESS EXIT');
  process.exit(0);
});

logger.warn('winston - I probably should only appear in console, not the log file?');

@yzaouchiak Любопытно, а это версия 0.6.2?

Имея такую ​​же проблему сейчас, необходимо завершить процесс и сделать запись в файле журнала. Было бы неплохо иметь опцию обратного вызова, которую мы могли бы использовать для выхода из процесса только после того, как сообщение было написано. А может он уже существует?

У меня такая же проблема с Winston 0.7.2.
Я безуспешно тестировал обходные пути setTimeout и обратного вызова.

Это та же проблема, что и # 288, а также проблема с log4js-node (https://github.com/nomiddlename/log4js-node/issues/148). Я думаю, проблема в том, что цикл событий не запускается после завершения обратного вызова process.exit, поэтому любые ожидающие асинхронные вызовы (например, запись файлов) не имеют возможности запускаться. Я буду очень рад, если кто-нибудь докажет, что я ошибаюсь, и предложит исправление.

Я готов посвятить время устранению этой проблемы, если мы сможем найти решение. Ключевой проблемой, по-видимому, является то, что WritableStreams не гарантирует сброса в process.exit () или необработанном исключении. Были ли исследованы какие-либо альтернативные решения? Похоже, мы могли бы кэшировать журналы в памяти до тех пор, пока WritableStream не иссякнет. Затем, если возникает исключение process.exit или неперехваченное исключение, мы можем синхронно записывать любые журналы, которые не были очищены. Это может привести к дублированию журналов, но, по крайней мере, предотвратит потерю журнала. Есть предположения?

Относится к № 288.

Есть обновления здесь? Все еще терпит неудачу для меня с ~ 0.9.0

Да, я все еще использую хак setTimeout (), упомянутый ранее @yzapuchlak :(

В любом случае, я не считаю это ошибкой Winston. Когда вы process.exit в свой код, вы принимаете решение полностью убить все, что еще выполняется при обработке. Если HTTP-запросы все еще выполняются, вы не предполагаете, что на них также будут даны ответы, так зачем предполагать, что сообщения журнала попадают в ваш журнал? Это то, как работает node, по какой-то причине все асинхронно. Если вы использовали подход обратного вызова или setTimeout, ничто не мешает вашему приложению записывать другую строку прямо перед тем, как ваш setTimeout будет выполнен или будет вызван обратный вызов.

Единственный способ обойти это - использовать синхронное ведение журнала, но тогда вы лишаетесь всей цели наличия асинхронной системы как простого оператора журнала, когда вы обрабатываете запросы.

Итак, я предлагаю закрыть эту проблему обычным исправлением. Если вы не хотите пропустить какие-либо сообщения журнала, убедитесь, что вы правильно очистили и закрыли приложение перед вызовом process.exit.

edit Также все ваши хаки setTimeout ошибочны и не решают проблему, поскольку вы не знаете, сколько времени потребуется, чтобы все данные были записаны в операционную систему, и как быстро ваши диски или ssds их обрабатывают. Единственное достойное решение здесь - прослушать событие потока drain и выйти из процесса. Но если ваше приложение постоянно ведет журнал, это может даже не вызываться в течение длительного периода; это просто еще один взлом, потому что вы не завершили работу приложения перед выходом.

Дело в том, что в настоящее время нет возможности ждать (обратный вызов / обещание / что-то еще), пока журналы будут сброшены. Также принудительное ведение журнала синхронизации позволит добавлять журналы в process.on('exit')

Если вы хотите иметь асинхронное ведение журнала во время жизненного цикла вашего приложения и синхронизацию журнала во время process.exit, вам следует создать новый экземпляр winston с пользовательской реализацией файла, который выполняет синхронизацию записи. И если вы хотите знать, когда что-то сбрасывается, вы должны прослушать событие слива потока.

Я попробую, спасибо!

Как бы то ни было, вы можете обойтись без использования setTimeout но вам нужно получить базовый _stream :

// log then exit(1)
logger.error("The thing to log", function(err) {
  var numFlushes = 0;
  var numFlushed = 0;
  Object.keys(logger.transports).forEach(function(k) {
    if (logger.transports[k]._stream) {
      numFlushes += 1;
      logger.transports[k]._stream.once("finish", function() {
        numFlushed += 1;
        if (numFlushes === numFlushed) {
          process.exit(1);
        }
      });
      logger.transports[k]._stream.end();
    }
  });
  if (numFlushes === 0) {
    process.exit(1);
  }
});

Как упоминалось выше, использования одной только функции обратного вызова _не достаточно_, чтобы она правильно сбрасывалась в файл. Мне это кажется ошибкой.

Обратите внимание, что я на самом деле слушаю событие finish : https://nodejs.org/api/stream.html#stream_event_finish, а не использую событие Winston flush или closed потому что этого тоже недостаточно для правильной регистрации: /

Попробуй это. В моем случае это работает очень хорошо. Вместо прямого вызова process.exit мы позволяем регистратору вызывать process.exit после очистки журнала.

logger.js:

var winston = require('winston');

winston.loggers.add('my-logger', {
    console: {
        level: 'debug',
        colorize: true,
        timestamp: true,
        handleExceptions: true
    },
    file: {
        level: 'info',
        colorize: false,
        timestamp: true,
        filename: 'file.log',
        handleExceptions: true
    }
});

var logger = winston.loggers.get('my-logger');


/* ******* *
 * EXPORTS
 * ******* */

exports.exitAfterFlush = function(code) {
    logger.transports.file.on('flush', function() {
        process.exit(code);
    });
};

exports.info = function() {
    logger.info.apply(this, arguments);
};

exports.warn = function() {
    logger.info.apply(this, arguments);
};

exports.error = function() {
    logger.info.apply(this, arguments);
};

в вашем коде:

var logger = require('./logger.js');
logger.exitAfterFlush(0);
logger.info('Done!');

Протестировано на NodeJS v4.1.2 и winston 1.1.0

Я использую что-то похожее на @ da-mkay.

function closeAllLoggersAndDisconnect() {
    "use strict";

    let openCount = 0;

    Object.keys(loggerInstance.transports).forEach((key) => {

        let transportInstance = loggerInstance.transports[key];

        if (typeof transportInstance.close === "function") {
            transportInstance.close();
            openCount++;
        }

        transportInstance.on("closed", () => {
            openCount--;
        });

        setInterval(() => {
            if (openCount === 0) {
                if (process.connected) {
                    process.disconnect();
                }
            }
        }, 100);
    });
}

в вашем коде:

winston.error("Error Occured", err, () => {
    closeAllLoggersAndDisconnect();
});

В идеале было бы неплохо, если бы я мог просто вызвать метод close для loggerInstance , но поскольку он генерирует событие closed как только он завершает вызов close метод для базовых транспортов, вместо того, чтобы после того, как они действительно закрылись, это не будет работать. Похоже, что это ошибка, когда регистратор может быть закрыт без полного закрытия базовых транспортов.

С помощью @Kegsay шаги и журналы записываются в файл.

Также успешно использую

По-прежнему есть эта проблема в версии 2.2.0 .

Это все еще не реализовано? Более 3-х лет. Я не хочу использовать выход из процесса.

Я понимаю, что это не проблема, но обязательно должна быть функция для завершения всех операций записи в файлы и закрытия всех открытых файлов, чтобы процесс мог выйти сам по себе, не вызывая его явно. Так сложно использовать такие вещи в производственных системах.

Повторяя, что это действительно требует решения со стороны Winston. Обеспечивает ли это синхронный перенос файлов или обеспечивает ловушку выключения для «безопасного» закрытия Winston, мне все равно, либо это было бы для меня удовлетворительным решением. Но отсутствие ничего просто делает невозможным запись журналов, а затем завершение работы и уверенность в том, что они действительно будут записаны.

Проблема с синхронным транспортом заключается в том, что выполнение вашего кода будет заблокировано до завершения ввода-вывода, что ограничивает производительность. Невозможно преобразовать асинхронную запись в блокирующую запись, что означает, что после выполнения асинхронной записи в журналы вам придется подождать, пока NodeJS не доберется до нее, а тем временем может быть выполнен другой код JS.

С другой стороны, обещания могут быть отменены синхронно, таймауты могут быть очищены синхронно, соединения файлов и базы данных могут быть закрыты синхронно, поэтому лучшим (более производительным) решением может быть отслеживание того, что необходимо отменить / очистить / closed и закройте их в обработчике исключений, который вызывает winston.log_and_exit() или дополнительный обратный вызов winston.log_and_exit() .

Конечно, было бы неплохо, если бы Уинстон отслеживал все, что вам нужно было закрыть в случае ошибки, но такой диспетчер задач, вероятно, был бы полезен сам по себе и, вероятно, заслуживает отдельной структуры (см. Закон Керли).

Я не понимаю, какое влияние здесь оказывает производительность. Процесс вот-вот будет остановлен, Winston нужно только вести бухгалтерию в последних строках журнала, в течение которых он может успешно заблокировать IMO.

Учитывая, сколько лет этой проблеме, и тот факт, что для нее есть обходное решение, я не собираюсь никого, кто решит эту проблему в Winston в ближайшее время.

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

Синхронная запись сообщений в файл, произошедших непосредственно перед ошибкой, потребовала бы, чтобы все сообщения записывались синхронно, и это проблема производительности.

Другие были обеспокоены тем, чтобы остановить запуск другого JS-кода после ошибки, но до того, как последние журналы будут записаны в файл.

Вариант, который может удовлетворить потребности каждого, - это написать собственный транспорт, который записывает асинхронно и сохраняет буфер сообщений, еще не подтвержденных как записанные (сброшенные) в файл, которые могут быть записаны в файл синхронно в случае ошибки (с риском дублирования сообщений. , в случае, если NodeJS уже завершил запись в файл, но сброшенное событие еще не обработано ...).

На самом деле сложно предоставить обработчик выключения для вызова, который ждал бы, пока все не будет сброшено, прежде чем вернуться и / или вызвать обратный вызов? Это решило бы практически все варианты использования.

Но позвольте мне также рассказать вам о моем варианте использования, почему меня не интересуют синхронные журналы. Тесты. Меня не волнует, занимают ли мои тесты секунду или две дольше. Меня действительно волнует, являются ли журналы недетерминированными, потому что они могут или не могут быть записаны в зависимости от того, насколько быстро узел решит завершить работу. Это плохо . Я полностью согласен с тем, что по умолчанию должен использоваться асинхронный режим. Я не согласен с тем, что это должен быть единственный вариант, особенно в свете подобных проблем внутри самого узла.

@mscharley вот как это делает log4js - есть функция log4js.shutdown которая может обеспечить обратный вызов. Он будет ждать, чтобы убедиться, что все аппендеры (я думаю, Winston называет их транспортами) завершили запись, прежде чем он вызовет обратный вызов. Кажется, у моих пользователей все работает нормально. Это требует поддержки со стороны приложений, поскольку они должны быть написаны так, чтобы они могли отвечать на вызовы завершения работы.

Я не пытаюсь продвигать log4js или говорить, что он лучше, чем winston, кстати - просто указываю, что этот подход может работать. Возможно, это не лучший подход.

Это о том, что делает winston.log_and_exit() . Обратите внимание, что log4js.shutdown() зависит от writable.end(complete) в случае добавлений на основе доступных для записи потоков ( appenders.filter(a => a.shutdown).forEach(a => a.shutdown(complete)); ), что по-прежнему является асинхронным завершением работы.

Я думаю, что в отношении комментария @mscharley преимущество состоит в том, что существует приложение fileSync , которое не требует использования shutdown() чтобы полные журналы записывались в файл, когда узел процесс завершается ...

Да, наличие транспорта fileSync будет полезно в некоторых ситуациях, даже если это приведет к снижению чистой производительности.

@jdthorpe Я думаю, что ваша идея о наличии библиотеки, которая обрабатывает закрытие вещей перед выключением, хорошая, но она все же не перекладывает ответственность с Winston на обеспечение метода ожидания, пока он сбросит все на диск (т. е. предоставить механизм для закрытия самого себя), который затем может быть объединен с такой библиотекой для объединения методов закрытия для различных библиотек.

Может ли этот билет хотя бы изменить документы, чтобы он не выглядел так, как будто он в настоящее время поддерживается? Я просто потратил 30 минут на отладку этой проблемы, которая, как предполагается, будет поддерживаться при поиске seriously в репо, она поддерживается только в README . Это просто похоже на неподдерживаемую функцию или ошибку, и обходные пути на самом деле не слишком приятны.

Когда это будет исправлено? Это существует уже 3 года и очень важно.

По крайней мере, давайте поместим обратный вызов в регистратор, который действительно работает.

Я бы сказал, что, возможно, написал общую функцию shutdown() для всех в качестве новой функции, и эта функция очень важна.

Да, это очень и очень важный вопрос.

+1 за это

Честно говоря, я думаю, что добавление shutdown(callback) кажется уместным, но с оговоркой, что транспорт должен его активно поддерживать. Индивидуальные транспорты являются «экспертами по информации» об их базовом механизме вывода; у них есть больше всего информации о том, как он должен полностью отключиться.

Все, что делает ядро winston - и, безусловно, все, что мы делаем на уровне пользователя - требует деталей реализации транспортов для утечки.

Итак, winston не должен выполнять работу ... но он действительно должен обеспечивать способ выполнения работы. Затем мы все можем пойти работать с авторами транспорта, чтобы сделать тяжелую работу.

Некоторый псевдокод для иллюстрации пункта ниже.

`` js
shutdown (callback) {
var transportCount = transports.length
вар закончил = 0;
// для каждого транспорта
if (transport.shutdown) {
transport.shutdown (function () {
// увеличить количество завершенных.
// если все закончено, вызываем исходный обратный вызов.
});
} еще {
// Транспорт (пока) не поддерживает это.
// увеличиваем счетчик завершения
}
}

Хотелось бы, чтобы это было исправлено в версии 3.x.

Вот мое решение (предполагается, что среда поддерживает async / await )


Для разового транспорта:

const logTransport = new winston.transports.File({filename: '/log/app.log'})

global.log = winston.createLogger({transports: [logTransport]})

// helper to exit with a given return code, but only after the logger is finished
// this will return a Promise that will never resolve, thus halting execution
log.exit = (exit = 5) => {
  return new Promise(() => {
    logTransport.on('finished', () => process.exit(exit))
  })
}



Для нескольких транспортов (непроверенных):

`` js
const logTransports = [новый файл winston.transports.File ({имя файла: '/log/app.log'})]

global.log = winston.createLogger ({транспорты: [logTransport]})

// помощник для выхода с заданным кодом возврата, но только после завершения работы регистратора
// это вернет обещание, которое никогда не будет разрешено, что остановит выполнение
log.exit = (exit = 5) => {
return new Promise (() => {
Promise.all (
logTransports.map (транспорт => новое обещание (resolve => transport.on ('завершено', разрешить)))
) .then (() => process.exit (выход))
})
}

</details>
<br>
Then, call with `await` like:

```js
try {
  something()
} catch(e) {   
  //do something with the error
  await log.exit(5) // <--- nothing will happen past this line as the promise will never resolve!
  // <--- process will have exited before it reaches here
  trySomethingElse() // <--- this will never be called, and control wont return to the calling code
}

Чтобы не быть побитым рекордом, winston-log-and-exit также решает эту проблему.

Только для очень и очень конкретных случаев использования. Я не мог использовать winston-log-and-exit, скажем, в AWS Lambda, где процесс не завершается, но он зависает между выполнениями, поэтому журналы все равно теряются. Также предполагается, что я знаю, какие сообщения являются моими последними, что не всегда может иметь место при успешном пути выполнения.

@mscharley подойдет ли указанное выше решение await для вашего варианта использования? Возможно, вместо log.exit() лучший api будет await log.finish() который будет ждать, пока все транспорты закончат запись, а затем позволит вам делать что угодно (вызовите process.exit , вызовите lamda done callback и т. д.)

Это в основном именно то, к чему мы настаиваем в этом выпуске, за исключением Winston. Почему это должен быть плагин? Похоже, это должно происходить чаще. Я не думаю, что то, что мы делаем, является чем-то особенным, но мы упираемся в эту стену в каждом проекте - вот почему в конце концов мы отошли от Winston. Потеря журналов, особенно в конце процесса, когда ошибки наиболее вероятны, кажется как минимум опасной.

log4js-node реализовал метод выключения с очисткой всех транспортов и принимает обратный вызов, такой как process.exit() . Можно ли что-то подобное добавить в winston?

log4js-node тогда

любые обновления? Проблема очень актуальна.

Для любой системы ведения журнала расчет:

  • Если вам абсолютно необходимы журналы и вы готовы платить за более медленное время отклика, используйте синхронный регистратор.
  • Если вы сами вызываете process.exit() , дождитесь очистки буферизованных сообщений. Для Winston пакет winston-log-and-exit сделает это за вас.
  • Если какой-то другой код вызывает process.exit() и ваша платформа имеет ловушку при выходе, используйте эту ловушку и дождитесь очистки буферизованных сообщений. winston-log-and-exit тоже может помочь в этом.
  • Если вы используете такую ​​платформу, как AWS Lambda, которая не имеет ловушки при выходе, то вы торгуете преимуществами платформы ради риска потери данных.

Между прочим, @ begin-again this метод log_and_exit() по сути совпадает с методом shutdown() в log-4js с дополнительной гарантией того, что предоставленное сообщение журнала будет зарегистрировано.

@jdthorpe Но winston-log-and-exit будет работать на Winston 3

@VRuzhentsov Ну, это проблема. Они действительно должны что-то с этим делать.

@jdthorpe Исправлено с помощью

const transport = new Transport();
const logger = createLogger({
  transports: [
    transport 
  ]
})

logger.finish = (exitCode) => {
  transport.on('finish', () => process.exit(exitCode));
  transport.close();
};

const shutDown = (exitCode) => {
  logger.info('Shutting down');
  logger.finish(exitCode);
};

shutDown(1);

Для меня работает следующее:

logger.info('winston - info logged');
logger.error('winston - error logged');
process.nextTick(() => {
    process.exit(0)
})

@ redhat-raptor. Это будет работать большую часть времени, но не всегда будет работать. Просто так случилось, что ваши буферы были очищены к моменту вызова nextTick (), но в зависимости от соединений, на которые полагаются ваши регистраторы, это может легко привести к потере сообщений ...

Этот код работал у меня:

            logger.error(`No value specified for ${value} variable! Node will exit now...`);
            logger._flush(() => {
                process.exit(1);
            })

Разве это не поддерживается в версии 3?

https://github.com/winstonjs/winston/blob/master/README.md#awaiting -logs-to-be-writing-in-winston

@danielweck Нет, он сломан: # 1629 # 1504!

6 лет, это верно, 6 лет для ошибки с пометкой _important_. Это впечатляет на грани.

Я использую обещание waitForWinston() :

const winston = require('winston');

const fileTransport = new winston.transports.File({ name: 'file', filename: FILE_PATH });
const consoleTransport = new winston.transports.Console({ name: 'console', stderrLevels: ['error'] });
const transports = [
    fileTransport,
    consoleTransport
];
winston.configure({
    level: 'verbose',
    transports,
    format: winston.format.cli()
});
winston.log('info', 'TEST MSG');
try {
    await waitForWinston();
} catch (err) {
    console.log(err);
}
process.exit(0);
const waitForWinston = async () => {
    return new Promise(async (resolve, _reject) => {
        for (const transport of transports) {
            try {
                await closeWinstonTransportAndWaitForFinish(transport);
            } catch (err) {
                console.log(err);
            }
        }
        resolve();
    });
};
const closeWinstonTransportAndWaitForFinish = async (transport) => {
    if (!transport.close) {
        // e.g. transport.name === 'console'
        return Promise.resolve();
    }
    // e.g. transport.name === 'file'

    return new Promise(async (resolve, _reject) => {
        transport._doneFinish = false;
        function done() {
            if (transport._doneFinish) {
                return; // avoid resolving twice, for example timeout after successful 'finish' event
            }
            transport._doneFinish = true;
            resolve();
        }
        setTimeout(() => { // TODO: use a cancellable setInterval instead
            done();
        }, 5000); // just in case the 'finish' event never occurs
        const finished = () => {
            done();
        };

/* Update: `stream.end()` does not flush pending writes, so this solution is inadequate.  For some reason, in recent tests `transport.close();` + `transport.once('finish', ...);` works just fine ... not sure why this works now though! (it used to fail!) */

/*
        if (transport._stream) {
            transport._stream.once('finish', finished);
            transport._stream.end();
        }
*/
            transport.once('finish', finished);
            transport.close();
    });  
};

Обновление: stream.end() не сбрасывает ожидающие записи, поэтому это решение неадекватно. По какой-то причине в недавних тестах transport.close(); + transport.once('finish', ...); работает нормально ... не уверен, почему это работает сейчас! (раньше не получалось!)

В моем рабочем решении, приведенном выше, ключ заключается в использовании:
transport._stream.once('finish', finished); transport._stream.end();
вместо:
transport.once('finish', finished); transport.close();
(добавленная стратегия тайм-аута специфична для моего варианта использования и, вероятно, является необязательной / избыточной в общем случае)

Более простой способ:

logger.error(`No value specified for ${missing_vars.join(',')} variable! Node will exit now...`, () => {
            process.exit(1);
        });

@danielweck Удалось ли вам когда-нибудь найти решение этой проблемы? Мы недавно обновились до Winston 3.x, но, возможно, придется вернуться к 2.x или найти другой регистратор без решения здесь.

@matttowerssonos , IIRC, все эти проблемы связаны с Winston @ 2. Учитывая длину этой цепочки и тот факт, что вы не интересуетесь исходным комментарием авторов, почему бы не начать новую цепочку с вашей проблемой?

Кстати, я не вижу проблем с потерянными журналами на Winston @ 3 , поэтому вы можете включить свою конфигурацию в свой новый выпуск.

@cjbarth Это не работает:

  process.on(type as any, (err: ErrorExtended) => {
    const processLogger: Logger = loggers.get('processLogger');

    processLogger.error(errorFormatter(err, type));

    processLogger.on('finish', function () {
      processLogger.end();
      console.log('never reaches here');
      process.exit(1);
    });
  });

processExit('uncaughtException');
// log and exit for unhandledRejection events.
processExit('unhandledRejection');

@stephanoparaskeva Если я не ошибаюсь, событие finish никогда не будет запущено на processLogger потому что вы никогда не вызываете processLogger.end() . Если вы это вызовете, то, когда Winston закончит регистрацию, должно сработать событие finish .

Я бы также использовал process.disconnect() вместо process.exit() , что позволяет очереди истощаться. Он выйдет автоматически, когда очередь будет опустошена.

@stephanoparaskeva Если я не ошибаюсь, событие finish никогда не будет запущено на processLogger потому что вы никогда не вызываете processLogger.end() . Если вы это вызовете, то, когда Winston закончит регистрацию, должно сработать событие finish .

Я бы также использовал process.disconnect() вместо process.exit() , что позволяет очереди истощаться. Он выйдет автоматически, когда очередь будет опустошена.

Попался, так что-то вроде этого?

process.on(type as any, (err: ErrorExtended) => {
  const processLogger: Logger = loggers.get('processLogger');

  processLogger.error(errorFormatter(err, type));
  processLogger.end()

  processLogger.on('finish', function () {
    process.disconnect();
  });
});

// log and exit for uncaughtException events.
processExit('uncaughtException');
// log and exit for unhandledRejection events.
processExit('unhandledRejection');

@stephanoparaskeva Так выглядит лучше.

Обычно я привязываю обработчик событий перед вызовом processLogger.end() , но это не имеет значения, потому что событие finish должно срабатывать только после того, как цикл событий повернется, и к этому времени обработчик будет привязан. Я просто думаю, что написание кода, в котором сначала привязан обработчик событий, делает его более понятным.

@cjbarth
Ой, как привязать к чему-нибудь обработчик событий?
Было бы это:

processLogger.on('finish', () => {
    this.process.disconnect();
  });

@stephanoparaskeva Да. Это правильный синтаксис для привязки функции

{
  this.process.disconnect();
}

К событию finish генерируемому объектом processLogger .

У меня работает: https://stackoverflow.com/a/59260151

Если вы не вызываете process.exit, а вместо этого выполняете надлежащее завершение работы, закрывая все соединения и ожидая, пока цикл событий не истощится, то проблем нет.

См. Это: https://stackoverflow.com/a/37592669, чтобы лучше понять, что имеет в виду @deedf . Следуя этому совету, я решил и эту проблему.

Тот факт, что событие финиша все еще не испускается спустя годы, в этот момент просто смущает. Будет больно переключать регистраторы и переписывать для них все мои настраиваемые транспорты.

Я не понимаю, как это еще не решено Уинстоном. У меня проблема, что только самый первый регистратор в моем коде регистрируется в Logstash (используя также winston-elasticsearch). Если я использую logger.end (), все регистрируется, но программа выходит слишком рано. попытался использовать все вышеперечисленные решения, и ни один из них не работал.
Я действительно беспомощен

Я не понимаю, как это еще не решено Уинстоном. У меня проблема, что только самый первый регистратор в моем коде регистрируется в Logstash (используя также winston-elasticsearch). Если я использую logger.end (), все регистрируется, но программа выходит слишком рано. попытался использовать все вышеперечисленные решения, и ни один из них не работал.
Я действительно беспомощен

Вы пробовали это ?

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Итак, наше решение этой проблемы - не вызывать process.exit ()?

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Итак, наше решение этой проблемы - не вызывать process.exit ()?

Да, в nodejs это всегда плохая идея, см. Https://stackoverflow.com/a/37592669

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Итак, наше решение этой проблемы - не вызывать process.exit ()?

Да, в nodejs это всегда плохая идея, см. Https://stackoverflow.com/a/37592669

Что ж, причина, по которой я лично использую process.exit, заключается в том, что я слушаю uncaughtException и unhandledRejection, чтобы регистрировать все мои транспорты, а затем закрывать приложение. Есть ли лучший способ решить эту проблему?

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Где вы видели, что я сказал, что использовал exit ()?

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Где вы видели, что я сказал, что использовал exit ()?

Извините, что предполагаю, что ваших способностей к чтению и пониманию достаточно, чтобы понять, о чем эта ошибка. Проверьте заголовок еще раз.

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Где вы видели, что я сказал, что использовал exit ()?

Извините, что предполагаю, что ваших способностей к чтению и пониманию достаточно, чтобы понять, о чем эта ошибка. Проверьте заголовок еще раз.

Вы, должно быть, очень заняты, если столкнетесь с проблемой, которая была открыта в течение 8 лет и не предложила никакой надлежащей помощи.

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Итак, наше решение этой проблемы - не вызывать process.exit ()?

Да, в nodejs это всегда плохая идея, см. Https://stackoverflow.com/a/37592669

Что ж, причина, по которой я лично использую process.exit, заключается в том, что я слушаю uncaughtException и unhandledRejection, чтобы регистрировать все мои транспорты, а затем закрывать приложение. Есть ли лучший способ решить эту проблему?

Я давно не пользовался Winston, но он все равно не регистрирует? если нет, не будет ли ошибка после регистрации работать повторно?

Я не понимаю, как люди не понимают, что эта «проблема» не «решена», потому что ее нет. Просто напишите правильный код, не вызывая exit (), и все будет в порядке.

Где вы видели, что я сказал, что использовал exit ()?

Извините, что предполагаю, что ваших способностей к чтению и пониманию достаточно, чтобы понять, о чем эта ошибка. Проверьте заголовок еще раз.

Вы, должно быть, очень заняты, если столкнетесь с проблемой, которая была открыта в течение 8 лет и не предложила никакой надлежащей помощи.

По крайней мере, я могу решать свои собственные проблемы, не ныть, как тупица.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги