Winston: Gagal masuk ke file saat memanggil process.exit (0)

Dibuat pada 25 Mar 2013  ·  87Komentar  ·  Sumber: winstonjs/winston

Ketika Anda telah mengkonfigurasi winston untuk masuk ke file dan Anda memanggil process.exit (0) dalam kode Anda, winston tidak pernah berakhir membuat file log dan menambahkan pesan log ke file tersebut.

Di dunia yang sempurna, winston dengan senang hati akan menangani kasus tepi ini dan menulis ke file, tetapi saya juga akan baik-baik saja dengan dapat memanggil flush pada instance logger untuk memaksa flush ke file secara manual.

Mungkin ada beberapa cara untuk 'menyiram' secara manual saat ini, tetapi itu tidak didokumentasikan dan saya tidak beruntung dengan secara manual menutup / mengakhiri / menghancurkan instance logger atau aliran dalamnya sejauh ini dengan cara yang benar-benar menghasilkan log sedang ditulis ke file ..

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

Komentar yang paling membantu

@danielweck Tidak, rusak: # 1629 # 1504!

6 tahun, benar, 6 tahun untuk bug yang ditandai _important_. Itu sangat mengesankan.

Semua 87 komentar

Dalam node metode console. * Menulis async, transport File adalah async. Anda menutup proses bahkan sebelum node memiliki data tertulis.

Pada hari Senin 25 Maret 2013 pukul 19.45, Yuri Zapuchlak menulis:

Ketika Anda telah mengkonfigurasi winston untuk masuk ke file dan Anda memanggil process.exit (0) dalam kode Anda, winston tidak pernah berakhir membuat file log dan menambahkan pesan log ke file tersebut.
Di dunia yang sempurna, winston dengan senang hati akan menangani kasus tepi ini dan menulis ke file, tetapi saya juga akan baik-baik saja dengan dapat memanggil flush pada instance logger untuk memaksa flush ke file secara manual.
Mungkin ada beberapa cara untuk 'menyiram' secara manual saat ini, tetapi itu tidak didokumentasikan dan saya tidak beruntung dengan secara manual menutup / mengakhiri / menghancurkan instance logger atau aliran dalamnya sejauh ini dengan cara yang benar-benar menghasilkan log sedang ditulis ke file ..
var winston = membutuhkan ('winston'); var logger = baru (winston.Logger) ({transportasi: [baru (winston.transports.Console) (), baru (winston.transports.File) ({nama file: 'winston.log'})]}); logger.info ('info dicatat'); logger.error ('kesalahan dicatat'); process.exit (0); // kedua log ditulis ke konsol, tetapi tidak ke file winston.log /

-
Balas email ini secara langsung atau lihat di GitHub (https://github.com/flatiron/winston/issues/228).

Hmm. Dalam kasus tersebut, jika seseorang harus menghentikan proses node tetapi perlu mencatat informasi tepat sebelum mereka membunuhnya, adalah meletakkan proses.exit () di dalam setTimeout () dengan durasi waktu yang cukup besar, satu-satunya hal yang dapat dilakukan untuk memastikan winston yang benar-benar menulis pesan ke file log?

Hanya untuk kejelasan, console.log dan teman - teman

@yzapuchlak Saya belum benar-benar menguji, tapi itulah yang saya lakukan juga.

@yzapuchlak setTimeout

setTimeout 2000 atau 5000 berfungsi dalam skrip pengujian sederhana saya, tetapi tidak saat saya mencoba menggunakannya dalam kode asli saya. Jadi, saya tidak tahu seberapa andal perbaikan potensial itu. Saya akan menggali masalah itu nanti jika saya tidak beruntung di bagian depan panggilan balik opsional.

@dtex Saya baru saja mencoba menggunakan callback opsional (seperti yang terlihat pada kode contoh berikut), tetapi masih tidak menghasilkan log yang ditulis ke file. File sebenarnya dibuat dalam kasus ini tetapi tidak ada log yang ditulis padanya.

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 Curious, apakah itu versi 0.6.2?

Memiliki masalah yang sama sekarang, perlu menghentikan proses dan membuat catatan di file log. Akan menyenangkan memiliki opsi panggilan balik, yang dapat kita gunakan untuk keluar dari proses hanya setelah pesan ditulis. Atau mungkin sudah ada?

Saya mengalami masalah yang sama, dengan Winston 0.7.2.
Saya menguji solusi setTimeout dan panggilan balik tanpa hasil.

Ini adalah masalah yang sama dengan # 288 dan juga masalah log4js-node (https://github.com/nomiddlename/log4js-node/issues/148). Saya pikir masalahnya adalah bahwa event loop tidak berjalan setelah callback process.exit selesai - sehingga panggilan async yang tertunda (seperti file menulis) tidak mendapatkan kesempatan untuk menjalankan. Saya akan sangat senang jika seseorang dapat membuktikan bahwa saya salah, dan memberikan solusi.

Saya bersedia mendedikasikan waktu untuk memperbaiki ini jika kami dapat menemukan solusi. Masalah utamanya tampaknya WritableStreams tidak menjamin pembilasan di process.exit () atau pengecualian yang tidak tertangani. Apakah ada solusi alternatif yang telah diselidiki? Sepertinya kami dapat menyimpan log dalam memori sampai WritableStream habis. Kemudian jika terjadi pengecualian process.exit atau uncaught, kita dapat secara sinkron menulis log apa pun yang belum dikosongkan. Ini mungkin menghasilkan log duplikat, tetapi setidaknya akan mencegah logloss. Ada pemikiran?

Terkait dengan # 288.

Ada pembaruan di sini? Masih gagal untuk saya dengan ~ 0.9.0

Ya, saya masih menggunakan retasan setTimeout () yang disebutkan oleh @yzapuchlak sebelumnya :(

Saya tidak benar-benar melihat ini sebagai bug winston. Ketika Anda process.exit dalam kode Anda, Anda telah membuat keputusan untuk benar-benar mematikan semua yang masih berjalan dalam pemrosesan. Jika masih ada permintaan HTTP yang berjalan, Anda tidak berasumsi bahwa ini juga akan dibalas, jadi mengapa berasumsi bahwa pesan log berakhir di log Anda? Ini hanyalah cara kerja node, semuanya asinkron karena suatu alasan. Jika jika Anda menggunakan pendekatan callback atau setTimeout, tidak ada yang mencegah aplikasi Anda untuk membuat log baris lain tepat sebelum setTimeout selesai atau callback dipanggil.

Satu-satunya cara untuk mengatasinya adalah dengan melakukan pencatatan log sinkron tetapi kemudian Anda mengalahkan seluruh tujuan memiliki sistem asinkron sebagai pernyataan log sederhana saat Anda menangani permintaan ..

Jadi yang saya sarankan adalah menutup masalah ini dengan tidak akan memperbaikinya. Jika Anda tidak ingin melewatkan pesan log apa pun, pastikan Anda membersihkan dan menutup aplikasi dengan benar sebelum memanggil process.exit.

edit Juga semua peretasan setTimeout Anda cacat dan tidak memperbaiki masalah karena Anda tidak tahu berapa lama waktu yang dibutuhkan agar semua data ditulis ke sistem operasi dan seberapa cepat disk atau ssds Anda memprosesnya. Satu-satunya solusi yang layak di sini adalah mendengarkan acara aliran drain dan keluar dari proses. Tetapi jika aplikasi Anda terus melakukan pencatatan, ini bahkan mungkin tidak dipanggil untuk waktu yang lama; p membuat ini hanya peretasan lain karena Anda tidak mematikan aplikasi dengan benar sebelum keluar.

Masalahnya adalah saat ini tidak ada cara untuk menunggu (panggilan balik / janji / apapun) untuk log yang akan dihapus. Memaksa logging sinkronisasi juga akan memungkinkan untuk menambahkan log di process.on('exit')

Jika Anda ingin memiliki pencatatan asinkron selama masa hidup aplikasi Anda dan menyinkronkan pencatatan selama process.exit, Anda harus membuat instance winston baru dengan implementasi file khusus yang menyinkronkan penulisan. Dan jika Anda ingin tahu kapan segala sesuatunya memerah, Anda harus mendengarkan acara pembuangan aliran.

Saya akan mencobanya, terima kasih!

Untuk apa nilainya, Anda dapat menyiasati penggunaan setTimeout tetapi Anda perlu mengambil _stream mendasarinya:

// 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);
  }
});

Seperti disebutkan di atas, penggunaan fungsi callback saja _tidak cukup_ untuk membuatnya di-flush dengan benar ke file. Ini terasa seperti bug bagi saya.

Perhatikan bahwa saya sebenarnya mendengarkan acara finish : https://nodejs.org/api/stream.html#stream_event_finish daripada menggunakan acara winston flush atau closed karena itu juga tidak cukup untuk membuatnya masuk dengan benar: /

Coba yang ini. Ini bekerja dengan cukup baik dalam kasus saya. Alih-alih memanggil process.exit secara langsung, kami membiarkan logger memanggil process.exit setelah log dibilas.

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);
};

dalam kode Anda:

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

Diuji pada NodeJS v4.1.2 dan winston 1.1.0

Saya menggunakan sesuatu yang mirip dengan @ 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);
    });
}

dalam kode Anda:

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

Idealnya, alangkah baiknya jika saya dapat memanggil metode close pada loggerInstance , tetapi karena metode itu mengeluarkan peristiwa closed segera setelah selesai memanggil close metode pada transport yang mendasari, bukannya setelah mereka benar-benar menutup, itu tidak akan bekerja. Tampaknya ini adalah bug yang logger dapat ditutup tanpa transport yang mendasarinya ditutup sepenuhnya.

Menggunakan langkah dan log @Kegsay ditulis ke file.

Juga menggunakan langkah-langkah @Kegsay dengan sukses ... dibungkus dengan fungsi saya sendiri.

Masih mengalami masalah ini pada versi 2.2.0 .

Apakah ini masih belum diterapkan? Berusia lebih dari 3 tahun. Saya tidak ingin menggunakan proses keluar.

Saya memahami bahwa ini bukan masalah tetapi pasti ada fungsi untuk menyelesaikan semua penulisan ke file dan menutup semua hal yang terbuka sehingga proses dapat keluar dengan sendirinya tanpa memanggilnya secara eksplisit. Sangat sulit untuk menggunakan hal-hal seperti itu dalam sistem produksi.

Menyuarakan bahwa ini benar-benar membutuhkan solusi dari pihak winston. Baik itu menyediakan transportasi file sinkron atau menyediakan pengait untuk menutup Winston 'dengan aman', saya tidak terlalu peduli, keduanya akan menjadi solusi yang memuaskan bagi saya. Tetapi tidak memiliki apa-apa hanya membuat tidak mungkin untuk menulis log dan kemudian berhenti dan yakinlah bahwa mereka benar-benar akan ditulis.

Masalah dengan pengangkutan sinkron, adalah bahwa eksekusi kode Anda akan diblokir sampai IO selesai, yang membatasi kinerja. Tidak ada cara untuk mengonversi penulisan asinkron menjadi penulisan pemblokiran, yang berarti setelah Anda menulis asinkron ke log, Anda harus menunggu sampai NodeJS menyiasatinya, dan sementara itu kode JS lainnya dapat dijalankan.

Di sisi lain, promise dapat dibatalkan secara sinkron, batas waktu dapat dihapus secara sinkron, koneksi file dan database dapat ditutup secara sinkron, sehingga solusi yang lebih baik (lebih berperforma) mungkin adalah melacak hal-hal yang perlu dibatalkan / dihapus / tutup dan tutup di penangan pengecualian yang memanggil winston.log_and_exit() , atau panggilan balik opsional ke winston.log_and_exit() .

Tentu alangkah baiknya jika Winston melacak semua hal yang perlu Anda tutup jika terjadi kesalahan, tetapi pengelola tugas seperti itu mungkin akan menjadi hal yang berguna dalam haknya sendiri, dan mungkin layak mendapatkan kerangka kerja terpisah (lihat Hukum Curley).

Saya tidak melihat bagaimana kinerja berdampak di sini. Prosesnya akan segera dihentikan, winston hanya perlu melakukan pembukuan pada baris log terakhir yang selama itu dapat dengan senang hati memblokir IMO.

Mengingat berapa lama masalah ini, dan fakta bahwa ada solusi untuk itu, saya tidak akan menunggu siapa pun yang menangani ini di winston dalam waktu dekat.

Kedengarannya seperti Anda dan saya berbicara (menulis) melintasi tujuan. Sepertinya Anda tertarik untuk menulis pesan akhir ke file secara sinkron, sedangkan kekhawatiran saya adalah memastikan bahwa log yang ditulis secara asinkron sebelum kesalahan ditulis ke file.

Menulis pesan ke file yang terjadi tepat sebelum kesalahan secara sinkron akan mengharuskan semua pesan ditulis secara sinkron, dan itulah masalah kinerja.

Yang lain khawatir tentang menghentikan kode JS lain agar tidak berjalan setelah kesalahan tetapi sebelum log terakhir ditulis ke file.

Sebuah opsi yang dapat memenuhi kebutuhan semua orang adalah dengan menulis transport khusus yang menulis secara asinkron, dan menyimpan buffer pesan yang belum dikonfirmasi sebagai tertulis (di-flush) ke file, yang dapat ditulis ke file secara sinkron saat terjadi kesalahan (dengan risiko duplikasi pesan , jika NodeJS sudah selesai menulis ke file, tetapi acara yang dibilas belum diproses ...).

Apakah sebenarnya sulit untuk menyediakan hook penutup untuk panggilan yang akan menunggu sampai semuanya hilang sebelum kembali dan / atau memanggil panggilan balik? Ini akan menyelesaikan hampir semua kasus penggunaan.

Namun izinkan saya juga memberi tahu Anda tentang kasus penggunaan saya, alasan saya tidak peduli dengan log sinkron. Tes. Saya tidak peduli jika pengujian saya membutuhkan waktu satu atau dua detik lebih lama untuk dijalankan. Saya peduli jika log non deterministik karena mereka mungkin atau mungkin tidak ditulis tergantung pada seberapa cepat node memutuskan untuk mematikan. Itu buruk . Saya setuju dengan sepenuh hati bahwa asynchronous harus menjadi default. Saya tidak setuju bahwa itu harus menjadi satu-satunya pilihan, terutama mengingat masalah seperti ini di dalam node itu sendiri.

@mscharley beginilah cara log4js melakukannya - ada fungsi log4js.shutdown yang dapat Anda panggil balik. Ini akan menunggu untuk memastikan semua appenders (menurut saya winston memanggil mereka transport) telah selesai menulis sebelum memanggil callback. Sepertinya berfungsi dengan baik untuk pengguna saya. Itu memang membutuhkan dukungan dari appenders, di mana mereka perlu ditulis sehingga mereka dapat menanggapi panggilan penonaktifan.

Saya tidak mencoba untuk mempromosikan log4js atau mengatakan bahwa itu lebih baik daripada winston, omong-omong - hanya menunjukkan bahwa pendekatan ini dapat bekerja. Ini mungkin bukan pendekatan terbaik.

Ini tentang apa yang dilakukan winston.log_and_exit() . Perhatikan bahwa log4js.shutdown() bergantung pada writable.end(complete) dalam hal penambahan berdasarkan aliran yang dapat ditulis, ( appenders.filter(a => a.shutdown).forEach(a => a.shutdown(complete)); ) yang masih merupakan penonaktifan asinkron.

Saya pikir sehubungan dengan komentar @mscharley , keuntungannya adalah bahwa ada fileSync appender, yang tidak memerlukan penggunaan shutdown() untuk memiliki log lengkap yang ditulis ke file ketika Node proses berhenti ...

Ya, memiliki transportasi fileSync akan berguna dalam beberapa situasi, bahkan jika itu akan menurunkan kinerja bersih.

@jdthorpe Saya pikir ide Anda tentang memiliki perpustakaan yang menangani hal-hal penutupan dengan bersih sebelum mematikan adalah bagus tetapi masih tidak mengalihkan tanggung jawab dari winston untuk menyediakan metode menunggu untuk membuang semuanya ke disk (yaitu, menyediakan mekanisme untuk menutup sendiri) yang kemudian dapat digabungkan dengan pustaka semacam itu untuk mengumpulkan metode tutup untuk berbagai pustaka.

Bisakah tiket ini setidaknya mengubah dokumen sehingga tidak terlihat seperti saat ini didukung Saya hanya menghabiskan 30 menit men-debug masalah ini yang dimaksudkan untuk didukung oleh ketika Anda mencari seriously di repo, itu hanya didukung di README . Ini sepertinya fitur yang tidak didukung atau bug dan solusinya tidak terlalu cocok.

Kapan ini akan diperbaiki? Ini telah ada selama 3 tahun sekarang dan cukup penting.

Setidaknya mari kita panggil kembali logger yang benar-benar berfungsi.

Saya akan mengatakan mungkin menulis fungsi shutdown() generik untuk semua orang sebagai fitur baru, dan fitur ini sangat penting.

Ya, ini adalah masalah yang sangat, sangat penting

1 untuk ini

Sejujurnya, saya pikir menambahkan shutdown(callback) tampaknya tepat tetapi dengan peringatan bahwa transportasi perlu mendukungnya secara aktif. Transportasi individu adalah "Ahli Informasi" tentang mekanisme keluaran yang mendasarinya; mereka memiliki paling banyak informasi tentang bagaimana itu harus dimatikan dengan bersih.

Apa pun yang dilakukan winston core - dan yang paling pasti apa pun yang kami lakukan di lahan pengguna - memerlukan detail implementasi pengangkutan agar bocor.

Jadi winston seharusnya tidak perlu melakukan pekerjaan ... tetapi benar-benar perlu menyediakan cara agar pekerjaan selesai. Kemudian kita semua bisa bekerja sama dengan penulis Transportasi untuk melakukan pekerjaan berat.

Beberapa psuedo-code mengilustrasikan poin di bawah ini.

`` js
shutdown (panggilan balik) {
var transportCount = transports.length
var selesai = 0;
// untuk setiap transportasi
if (transport.shutdown) {
transport.shutdown (function () {
// tingkatkan jumlah akhir.
// jika semua sudah selesai, panggil callback asli.
});
} lain {
// Transport belum (belum) mendukungnya.
// peningkatan penghitung selesai
}
}

Akan sangat senang melihat ini diperbaiki di v3.x.

Inilah solusi saya (asumsikan lingkungan yang mendukung async / await )


Untuk transportasi tunggal:

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))
  })
}



Untuk beberapa transportasi (belum teruji):

`` js
const logTransports = [winston.transports.File baru ({namafile: '/log/app.log'})]

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

// helper untuk keluar dengan kode pengembalian yang diberikan, tetapi hanya setelah logger selesai
// ini akan mengembalikan Promise yang tidak akan pernah terselesaikan, sehingga menghentikan eksekusi
log.exit = (keluar = 5) => {
kembalikan Janji baru (() => {
Promise.all (
logTransports.map (transport => janji baru (menyelesaikan => transport.on ('selesai', menyelesaikan)))
). lalu (() => proses.exit (keluar))
})
}

</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
}

Bukan menjadi rekor yang rusak, tetapi winston-log-and-exit juga menyelesaikan masalah ini

Hanya untuk kasus penggunaan yang sangat, sangat spesifik. Saya tidak dapat menggunakan winston-log-and-exit, katakanlah AWS Lambda di mana prosesnya tidak keluar, tetapi berhenti di antara eksekusi sehingga log masih hilang. Ini juga mengasumsikan saya tahu pesan mana yang merupakan pesan terakhir saya yang mungkin tidak selalu terjadi di jalur eksekusi yang berhasil.

@mscharley akankah solusi await atas berfungsi untuk kasus penggunaan Anda? Mungkin alih-alih log.exit() api yang lebih baik akan await log.finish() yang akan menunggu sampai semua transportasi selesai menulis dan kemudian membiarkan Anda melakukan apa pun (panggil process.exit , panggil lamda done callback, dll)

Pada dasarnya itulah yang kami dorong dalam masalah ini, kecuali di dalam Winston. Mengapa ini menjadi plugin? Sepertinya sesuatu yang harus lebih sering muncul. Saya tidak merasa apa yang kami lakukan adalah sesuatu yang istimewa, namun kami telah mencapai tembok ini di setiap proyek - itulah sebabnya kami akhirnya pindah dari Winston. Kehilangan log, terutama di akhir proses - di mana kesalahan paling mungkin terjadi - tampaknya berbahaya setidaknya.

log4js-node telah mengimplementasikan metode shutdown dengan membersihkan semua transport dan mengambil callback seperti process.exit() . Bisakah sesuatu seperti ini ditambahkan ke winston?

log4js-node kemudian

ada pembaruan? Masalahnya sangat aktual.

Untuk sistem logging apa pun, kalkulusnya adalah:

  • Jika Anda benar-benar harus memiliki log dan bersedia membayar biaya waktu respons yang lebih lambat, gunakan logger sinkron
  • Jika Anda sendiri yang memanggil process.exit() , tunggu sampai pesan yang di-buffer dihapus. Untuk winston, paket winston-log-and-exit melakukannya untuk Anda.
  • Jika beberapa kode lain memanggil process.exit() dan platform Anda memiliki hook on-exit, gunakan hook itu dan tunggu sampai pesan yang di-buffer dihapus. winston-log-and-exit juga dapat membantu.
  • Jika Anda menggunakan platform seperti AWS Lambda yang tidak memiliki on-exit hook, maka Anda memperdagangkan manfaat platform dengan risiko kehilangan data.

Kebetulan, @ begin-again ini metode log_and_exit() pada dasarnya sama dengan metode shutdown() log-4js dengan jaminan tambahan bahwa pesan log yang diberikan akan dicatat.

@jdthorpe Tapi winston-log-and-exit tidak akan bekerja dengan mudah di winston 3

@VRuzhentsov Oh, itu masalahnya. Mereka harus benar-benar melakukan sesuatu tentang itu.

@jdthorpe Diperbaiki dengan

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);

Pekerjaan berikut untuk saya:

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

@ redhat-raptor. Itu akan berhasil sebagian besar waktu, tetapi itu tidak dijamin akan berhasil sepanjang waktu. Kebetulan buffer Anda dihapus pada saat nextTick () dipanggil, tetapi bergantung pada koneksi yang diandalkan oleh logger Anda, ini dapat dengan mudah mengakibatkan pesan yang hilang ...

Kode ini berfungsi untuk saya:

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

Bukankah ini secara native didukung di v3?

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

@danielweck Tidak, rusak: # 1629 # 1504!

6 tahun, benar, 6 tahun untuk bug yang ditandai _important_. Itu sangat mengesankan.

Saya menggunakan waitForWinston() Promise:

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();
    });  
};

Perbarui: stream.end() tidak menghapus penulisan yang tertunda, jadi solusi ini tidak memadai. Untuk beberapa alasan, dalam pengujian baru-baru ini transport.close(); + transport.once('finish', ...); berfungsi dengan baik ... meskipun tidak yakin mengapa ini berfungsi sekarang! (dulu gagal!)

Dalam solusi kerja saya di atas, kuncinya adalah menggunakan:
transport._stream.once('finish', finished); transport._stream.end();
dari pada:
transport.once('finish', finished); transport.close();
(strategi batas waktu tambahan khusus untuk kasus penggunaan saya, dan mungkin opsional / berlebihan dalam kasus umum)

Cara yang lebih mudah:

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

@danielweck Pernahkah Anda menemukan solusi untuk ini? Kami baru saja memutakhirkan ke Winston 3.x tetapi mungkin harus kembali ke 2.x atau menemukan pencatat yang berbeda tanpa solusi di sini.

@matttowerssonos , IIRC, semua masalah ini terkait dengan Winston @ 2. Mengingat panjang utas ini, dan fakta bahwa Anda tidak menanyakan tentang komentar poster asli, mengapa tidak memulai utas baru dengan masalah Anda?

BTW, saya tidak melihat masalah apa pun dengan log yang hilang di Winston @ 3 , jadi Anda mungkin ingin memasukkan konfigurasi Anda dalam terbitan baru Anda.

@cjbarth Ini tidak bekerja:

  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 Jika saya tidak salah, peristiwa finish tidak akan pernah diaktifkan pada processLogger karena Anda tidak pernah memanggil processLogger.end() . Jika Anda memanggilnya, maka, ketika Winston selesai melakukan logging, peristiwa finish harus diaktifkan.

Saya juga akan menggunakan process.disconnect() alih-alih process.exit() , yang memungkinkan antrian habis. Ini akan keluar secara otomatis ketika antrian dikeringkan.

@stephanoparaskeva Jika saya tidak salah, peristiwa finish tidak akan pernah diaktifkan pada processLogger karena Anda tidak pernah memanggil processLogger.end() . Jika Anda memanggilnya, maka, ketika Winston selesai melakukan logging, peristiwa finish harus diaktifkan.

Saya juga akan menggunakan process.disconnect() alih-alih process.exit() , yang memungkinkan antrian habis. Ini akan keluar secara otomatis ketika antrian dikeringkan.

Gotcha, jadi seperti ini?

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');

@hanopaskeva Itu terlihat lebih baik.

Saya biasanya akan mengikat event handler sebelum memanggil processLogger.end() , tetapi itu seharusnya tidak menjadi masalah karena event finish harus diaktifkan hanya setelah event loop berputar, pada saat itu handler akan terikat. Saya hanya berpikir menulis kode di mana event handler terikat terlebih dahulu membuatnya lebih jelas.

@bayu_joo
Oh, bagaimana Anda mengikat event handler ke sesuatu?
Apakah itu:

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

@hanifahmuhammad Ya. Itu adalah sintaks yang benar untuk mengikat fungsi

{
  this.process.disconnect();
}

Ke acara finish yang dipancarkan oleh objek processLogger .

Ini berfungsi untuk saya: https://stackoverflow.com/a/59260151

Jika Anda tidak memanggil process.exit tetapi melakukan shutdown yang benar, dengan menutup semua koneksi dan menunggu event loop habis, maka tidak ada masalah sama sekali.

Lihat ini: https://stackoverflow.com/a/37592669 untuk mendapatkan pemahaman yang lebih baik tentang apa yang dimaksud @deedf . Mengikuti saran ini, meringankan masalah ini untuk saya juga.

Fakta bahwa event finis masih belum keluar setelah bertahun-tahun hanya memalukan pada saat ini. Ini akan menyebalkan harus mengganti penebang dan menulis ulang semua transportasi khusus saya untuk mereka.

Saya tidak mengerti bagaimana ini belum diselesaikan oleh winston. Saya memiliki masalah bahwa hanya logger pertama dalam kode saya yang dapat login ke Logstash (juga menggunakan winston-elasticsearch). Jika saya menggunakan logger.end () maka semuanya akan dicatat, tetapi program keluar terlalu dini. mencoba menggunakan semua solusi di atas, dan tidak ada yang benar-benar berhasil.
Saya benar-benar tidak berdaya

Saya tidak mengerti bagaimana ini belum diselesaikan oleh winston. Saya memiliki masalah bahwa hanya logger pertama dalam kode saya yang dapat login ke Logstash (juga menggunakan winston-elasticsearch). Jika saya menggunakan logger.end () maka semuanya akan dicatat, tetapi program keluar terlalu dini. mencoba menggunakan semua solusi di atas, dan tidak ada yang benar-benar berhasil.
Saya benar-benar tidak berdaya

Apakah Anda mencoba ini ?

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Jadi solusi kami untuk masalah ini adalah dengan tidak memanggil proses.exit ()?

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Jadi solusi kami untuk masalah ini adalah dengan tidak memanggil proses.exit ()?

Ya, selalu merupakan ide yang buruk di nodejs, lihat https://stackoverflow.com/a/37592669

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Jadi solusi kami untuk masalah ini adalah dengan tidak memanggil proses.exit ()?

Ya, selalu merupakan ide yang buruk di nodejs, lihat https://stackoverflow.com/a/37592669

Alasan saya secara pribadi menggunakan process.exit adalah karena saya mendengarkan uncaughtException dan unhandledRejection untuk masuk ke semua transport saya, lalu keluar dari aplikasi. Apakah ada cara yang lebih baik untuk menyelesaikan masalah ini?

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Di mana Anda melihat saya mengatakan saya menggunakan exit ()?

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Di mana Anda melihat saya mengatakan saya menggunakan exit ()?

Maaf karena mengasumsikan kemampuan membaca dan pemahaman Anda cukup untuk memahami tentang bug ini. Periksa kembali judulnya.

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Di mana Anda melihat saya mengatakan saya menggunakan exit ()?

Maaf karena mengasumsikan kemampuan membaca dan pemahaman Anda cukup untuk memahami tentang bug ini. Periksa kembali judulnya.

Anda pasti sangat sibuk jika Anda menghadapi masalah yang telah terbuka selama 8 tahun dan tidak menawarkan bantuan yang tepat sama sekali.

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Jadi solusi kami untuk masalah ini adalah dengan tidak memanggil proses.exit ()?

Ya, selalu merupakan ide yang buruk di nodejs, lihat https://stackoverflow.com/a/37592669

Alasan saya secara pribadi menggunakan process.exit adalah karena saya mendengarkan uncaughtException dan unhandledRejection untuk masuk ke semua transport saya, lalu keluar dari aplikasi. Apakah ada cara yang lebih baik untuk menyelesaikan masalah ini?

Saya sudah lama tidak menggunakan winston, tetapi apakah itu tidak akan masuk akal? jika tidak, tidakkah memunculkan kembali kesalahan setelah masuk itu berfungsi?

Saya tidak mengerti bagaimana orang tidak mengerti bahwa "masalah" ini belum "diselesaikan" karena tidak ada. Cukup tulis kode yang benar dengan tidak memanggil exit () dan Anda akan baik-baik saja.

Di mana Anda melihat saya mengatakan saya menggunakan exit ()?

Maaf karena mengasumsikan kemampuan membaca dan pemahaman Anda cukup untuk memahami tentang bug ini. Periksa kembali judulnya.

Anda pasti sangat sibuk jika Anda menghadapi masalah yang telah terbuka selama 8 tahun dan tidak menawarkan bantuan yang tepat sama sekali.

Setidaknya saya bisa menyelesaikan masalah saya sendiri tanpa merengek seperti anak nakal yang berhak.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat