Winston: فشل تسجيل الدخول إلى الملف عند استدعاء process.exit (0)

تم إنشاؤها على ٢٥ مارس ٢٠١٣  ·  87تعليقات  ·  مصدر: winstonjs/winston

عندما تقوم بتهيئة winston لتسجيل الدخول إلى ملف وتقوم باستدعاء process.exit (0) في التعليمات البرمجية الخاصة بك ، فإن winston لا ينتهي أبدًا بإنشاء ملف السجل وإلحاق رسائل السجل بالملف.

في عالم مثالي ، سوف يتعامل Winston بسعادة مع حالة الحافة هذه ويكتب إلى الملف ، ولكن سأكون على ما يرام أيضًا مع القدرة على استدعاء flush على مثيل المسجل من أجل فرض تدفق يدويًا إلى الملف.

قد تكون هناك طريقة ما "للتدفق" يدويًا في الوقت الحالي ، ولكن لم يتم توثيقها ولم يحالفني الحظ يدويًا لإغلاق / إنهاء / تدمير مثيل المسجل أو التدفقات الداخلية الخاصة به حتى الآن بطريقة تؤدي في الواقع إلى السجلات يتم كتابتها في ملف ..

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 سنوات للخلل الذي تم وضع علامة عليه "هام". إنه خط حدودي مثير للإعجاب.

ال 87 كومينتر

في عقدة وحدة التحكم. أساليب تكتب غير متزامن ، نقل الملف غير متزامن. أنت تغلق العملية قبل أن تقوم العقدة بكتابة البيانات.

في يوم الاثنين 25 مارس 2013 الساعة 19:45 ، كتب يوري زابوتشلاك:

عندما تقوم بتهيئة winston لتسجيل الدخول إلى ملف وتقوم باستدعاء process.exit (0) في التعليمات البرمجية الخاصة بك ، فإن winston لا ينتهي أبدًا بإنشاء ملف السجل وإلحاق رسائل السجل بالملف.
في عالم مثالي ، سوف يتعامل Winston بسعادة مع حالة الحافة هذه ويكتب إلى الملف ، ولكن سأكون على ما يرام أيضًا مع القدرة على استدعاء flush على مثيل المسجل من أجل فرض تدفق يدويًا إلى الملف.
قد تكون هناك طريقة ما "للتدفق" يدويًا في الوقت الحالي ، ولكن لم يتم توثيقها ولم يحالفني الحظ يدويًا لإغلاق / إنهاء / تدمير مثيل المسجل أو التدفقات الداخلية الخاصة به حتى الآن بطريقة تؤدي في الواقع إلى السجلات يتم كتابتها في ملف ..
var winston = يتطلب ('winston') ؛ var logger = new (winston.Logger) ({transports: [new (winston.transports.Console) ()، new (winston.transports.File) ({filename: 'winston.log'})]})؛ logger.info ("معلومات مسجلة") ؛ logger.error ("تم تسجيل الخطأ") ؛ process.exit (0) ؛ // تتم كتابة السجلين على وحدة التحكم ، ولكن ليس إلى ملف winston.log /

-
قم بالرد على هذه الرسالة الإلكترونية مباشرةً أو اعرضها على GitHub (https://github.com/flatiron/winston/issues/228).

همم. في هذه الحالة ، إذا كان على المرء أن يقتل عملية عقدة ولكنه يحتاج إلى تسجيل المعلومات مباشرة قبل أن يقتلها ، فإنه يضع العملية. exit () داخل setTimeout () مع مدة زمنية كبيرة بما يكفي ، الشيء الوحيد الذي يمكن للمرء فعله لضمان أن وينستون يكتب رسائل بالفعل إلى ملف السجل؟

فقط من أجل الوضوح، console.log والأصدقاء هم متزامن .

yzapuchlak لم أختبر بالفعل ، لكن هذا ما أفعله أيضًا.

yzapuchlak setTimeout سيعمل _probably__ بدون مشاكل ، لكنني أعتقد أنه سيكون من الحكمة استخدام معلمة رد الاتصال الاختيارية بدلاً من ذلك.

يعمل 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 (https://github.com/nomiddlename/log4js-node/issues/148). أعتقد أن المشكلة تكمن في أن حلقة الحدث لا تعمل بمجرد انتهاء عملية رد الاتصال process.exit - لذلك لا تحصل أي مكالمات معلقة غير متزامنة (مثل عمليات كتابة الملف) على فرصة للتشغيل. سأكون سعيدًا جدًا إذا تمكن شخص ما من إثبات أنني مخطئ ، والتوصل إلى حل.

أنا على استعداد لتكريس الوقت لإصلاح هذا إذا تمكنا من التوصل إلى حل. يبدو أن المشكلة الرئيسية هي أن WritableStreams لا يضمن التدفق على process.exit () أو استثناء غير معالج. هل تم التحقيق في أي حلول بديلة؟ يبدو أنه يمكننا تخزين السجلات في الذاكرة مؤقتًا حتى يتم استنزاف WritableStream. ثم في حالة حدوث process.exit أو استثناء غير معلوم ، يمكننا كتابة أي سجلات لم يتم استنزافها بشكل متزامن. قد ينتج عن هذا سجلات مكررة ، ولكنه على الأقل يمنع فقدان السجل. أي أفكار؟

ذات صلة بـ # 288.

أي تحديثات هنا؟ ما زلت أخفق مع ~ 0.9.0

نعم ، ما زلت أستخدم الاختراق setTimeout () الذي ذكره yzapuchlak سابقًا :(

لا أرى هذا حقًا على أنه خطأ في وينستون على أي حال. عند process.exit في التعليمات البرمجية كنت قد اتخذت القرار تماما قتل كل ما لا يزال يعمل على معالجة. إذا كانت لا تزال هناك طلبات HTTP قيد التشغيل ، فلا تفترض أنه سيتم الرد عليها أيضًا ، فلماذا تفترض أن رسائل السجل تنتهي في السجل الخاص بك؟ هذه هي الطريقة التي تعمل بها العقدة بشكل غير متزامن لسبب ما. إذا استخدمت طريقة رد الاتصال أو طريقة setTimeout ، فلا يوجد ما يمنع تطبيقك من تسجيل سطر آخر قبل انتهاء setTimeout أو استدعاء رد الاتصال.

الطريقة الوحيدة للتغلب على ذلك هي أن يكون لديك تسجيل متزامن ولكنك بعد ذلك تهزم الغرض الكامل من وجود نظام غير متزامن كبيان سجل بسيط عندما تتعامل مع الطلبات ..

لذا فإن ما أقترحه هو إغلاق هذه المشكلة بحل متعود. إذا كنت لا تريد أن تخطئ في أي رسائل سجل ، فتأكد من تنظيف التطبيق وإغلاقه بشكل صحيح قبل استدعاء process.exit.

تحرير أيضًا جميع عمليات الاختراق الخاصة بـ setTimeout معيبة ولا تصلح المشكلة نظرًا لأنه ليس لديك أي فكرة عن المدة التي ستستغرقها كتابة جميع البيانات في نظام التشغيل ومدى سرعة معالجة الأقراص أو أقراص SSDS. الحل الوحيد اللائق هنا هو الاستماع إلى حدث الدفق drain والخروج من العملية. ولكن إذا كان التطبيق الخاص بك يقوم بتسجيل الدخول باستمرار ، فقد لا يتم استدعاء هذا لفترة طويلة ؛ p مما يجعل هذا مجرد اختراق آخر لأنك لم تقم بإغلاق التطبيق الخاص بك بشكل صحيح قبل الخروج.

الشيء هو أنه لا توجد طريقة حاليًا للانتظار (رد الاتصال / الوعد / أيا كان) حتى يتم مسح السجلات. سيؤدي فرض تسجيل المزامنة أيضًا إلى إمكانية إضافة السجلات في process.on('exit')

إذا كنت تريد أن يكون لديك تسجيل غير متزامن خلال فترة حياة التطبيق الخاص بك ومزامنة التسجيل أثناء العملية. 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 يتم كتابة الخطوات والسجلات في ملف.

أيضًا باستخدام خطوات Kegsay بنجاح ... ملفوفة في وظيفتي الخاصة.

لا تزال هذه المشكلة في الإصدار 2.2.0 .

هل هذا ما زال غير مطبق؟ أكثر من 3 سنوات. لا أريد استخدام عملية الخروج.

أفهم أن هذه ليست مشكلة ولكن يجب أن تكون هناك بالتأكيد وظيفة لإنهاء جميع عمليات الكتابة في الملفات وإغلاق أي عناصر مفتوحة بحيث يمكن للعملية الخروج من تلقاء نفسها دون الاتصال بها صراحة. من الصعب جدًا استخدام مثل هذه الأشياء في أنظمة الإنتاج.

مرددًا أن هذا يحتاج حقًا إلى حل من جانب ونستون. سواء أكان ذلك يوفر نقلًا متزامنًا للملفات أو يوفر خطافًا للإغلاق لإغلاق Winston "بأمان" ، فأنا لا أهتم حقًا ، فسيكون أي منهما حلاً مرضيًا بالنسبة لي. لكن عدم وجود أي شيء يجعل من المستحيل كتابة السجلات ثم الاستقالة والتأكد من أنها ستكتب بالفعل.

الشيء مع النقل المتزامن ، هو أنه سيتم حظر تنفيذ الكود الخاص بك حتى يكتمل الإدخال / الإخراج ، مما يحد من الأداء. لا توجد طريقة لتحويل كتابة غير متزامنة إلى كتابة محظورة ، مما يعني أنه بمجرد أن تكتب غير متزامن إلى السجلات ، عليك الانتظار حتى يصل NodeJS إليها ، وفي الوقت نفسه قد يتم تنفيذ كود JS آخر.

من ناحية أخرى ، يمكن إلغاء الوعود بشكل متزامن ، ويمكن مسح المهلات بشكل متزامن ، ويمكن إغلاق اتصالات الملفات وقاعدة البيانات بشكل متزامن ، لذلك قد يكون الحل الأفضل (الأكثر أداءً) هو تتبع الأشياء التي يجب إلغاؤها / مسحها / أغلقها وأغلقها في معالج الاستثناء الذي يستدعي winston.log_and_exit() ، أو رد الاتصال الاختياري إلى winston.log_and_exit() .

من المؤكد أنه سيكون من الجيد أن يتتبع وينستون كل الأشياء التي قد تحتاج إلى إغلاقها في حالة حدوث خطأ ، ولكن من المحتمل أن يكون مدير المهام هذا شيئًا مفيدًا في حد ذاته ، وربما يستحق إطار عمل منفصل (انظر قانون كيرلي).

لا أرى كيف يكون للأداء أي تأثير هنا. العملية على وشك الموت ، يحتاج Winston فقط إلى إمساك الدفاتر في سطور السجل النهائية ، والتي يمكن خلالها حظر IMO بسعادة.

نظرًا لعمر هذه المشكلة ، وحقيقة وجود حل بديل لها ، فأنا لا أتحمل أي شخص يعالج هذا الأمر في Winston في أي وقت قريبًا.

يبدو أنك وأنا نتحدث (نكتب) لأغراض مختلفة. يبدو أنك مهتم بكتابة الرسائل النهائية بشكل متزامن في الملف ، بينما كان قلقي هو التأكد من كتابة السجلات التي تمت كتابتها بشكل غير متزامن قبل كتابة الخطأ في الملف.

تتطلب كتابة الرسائل في الملف التي حدثت قبل الخطأ مباشرة بشكل متزامن كتابة جميع الرسائل بشكل متزامن ، وهذه هي مشكلة الأداء.

كان الآخرون قلقين بشأن إيقاف تشغيل كود JS الآخر بعد حدوث خطأ ولكن قبل كتابة السجلات الأخيرة في الملف.

أحد الخيارات التي قد تلبي احتياجات الجميع هو كتابة وسيلة نقل مخصصة تكتب بشكل غير متزامن ، وتحتفظ بمخزن مؤقت للرسائل التي لم يتم تأكيدها بعد على أنها مكتوبة (مسحوبة) في الملف ، والتي يمكن كتابتها لتقديمها بشكل متزامن عند حدوث خطأ (مع المخاطرة بتكرار الرسائل ، في حالة انتهاء NodeJS بالفعل من الكتابة إلى ملف ، ولكن لم تتم معالجة الحدث المتدفق بعد ...).

هل من الصعب حقًا توفير خطاف إغلاق للاتصال الذي سينتظر حتى يتم مسح كل شيء قبل العودة و / أو استدعاء رد الاتصال؟ هذا من شأنه أن يحل إلى حد كبير كل حالة استخدام.

لكن اسمحوا لي أيضًا أن أخبركم عن حالة الاستخدام الخاصة بي ، والسبب في عدم اهتمامي بالسجلات المتزامنة. الاختبارات. لا أهتم إذا كانت اختباراتي تستغرق ثانية أو ثانيتين. يهمني ما إذا كانت السجلات غير حتمية لأنها قد يتم كتابتها أو لا يتم كتابتها اعتمادًا على السرعة التي تقرر العقدة إغلاقها بالضبط. هذا سيء . أوافق تمامًا على أن غير المتزامن يجب أن يكون الافتراضي. لا أوافق على أنه يجب أن يكون الخيار الوحيد ، خاصة في ضوء مشكلات مثل هذه داخل العقدة نفسها.

mscharley هذه هي الطريقة التي يقوم بها log4js - هناك وظيفة log4js.shutdown يمكنك توفير رد اتصال. سوف ينتظر للتأكد من أن جميع المُلحقين (يسميهم وينستون وسائل النقل ، على ما أعتقد) قد انتهوا من الكتابة قبل أن يستدعي رد الاتصال. يبدو أنه يعمل بشكل جيد لمستخدمي. إنه يتطلب دعمًا من المُلحقين ، حيث يجب كتابتهم حتى يتمكنوا من الرد على مكالمات الإغلاق.

بالمناسبة ، لا أحاول الترويج لـ 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 إلى القيام بهذا العمل ... لكنه يحتاج حقًا إلى توفير طريقة لإنجاز العمل. ثم يمكننا جميعًا العمل مع مؤلفي النقل للقيام بالأعمال الثقيلة.

بعض رموز psuedo لتوضيح النقطة أدناه.

شبيبة
اغلاق (رد الاتصال) {
var transportCount = transports.length
انتهى var = 0 ؛
// لكل عملية نقل
إذا (transport.shutdown) {
transport.shutdown (الوظيفة () {
// زيادة العد النهائي.
// إذا انتهى كل شيء ، اتصل بمعاودة الاتصال الأصلي.
}) ؛
} آخر {
// لا يدعمها النقل (حتى الآن).
// زيادة عداد الانتهاء
}
}

أحب أن أرى هذا مثبتًا في الإصدار 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))
  })
}



بالنسبة لعمليات النقل المتعددة (غير المختبرة):

شبيبة
const logTransports = [new winston.transports.File ({filename: '/log/app.log'})]

global.log = winston.createLogger ({النقل: [logTransport]})

// المساعد للخروج برمز إرجاع محدد ، ولكن فقط بعد انتهاء المسجل
// سيعيد هذا الوعد الذي لن يحل أبدًا ، وبالتالي يوقف التنفيذ
log.exit = (خروج = 5) => {
إرجاع الوعد الجديد (() => {
الوعد. all (
logTransports.map (النقل => وعد جديد (حل => النقل على ('انتهى' ، حل)))
). ثم (() => 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() ، يمكن لواجهة برمجة أفضل أن تنتظر await log.finish() حتى تنتهي جميع عمليات النقل من الكتابة ثم تتيح لك القيام بأي شيء (اتصل بـ process.exit ، اتصل بـ lamda done رد الاتصال ، وما إلى ذلك)

هذا هو بالضبط ما كنا ندفع من أجله في هذه القضية ، باستثناء داخل وينستون. لماذا قد يكون هذا البرنامج المساعد؟ يبدو أنه شيء يجب أن يظهر كثيرًا. لا أشعر أن ما نقوم به هو أي شيء مميز ، لكننا اصطدمنا بهذا الجدار في كل مشروع - ولهذا السبب ابتعدنا عن وينستون في النهاية. يبدو فقدان السجلات ، خاصة في نهاية العملية - حيث يرجح حدوث الأخطاء - خطيرًا على الأقل.

نفذ log4js-node طريقة إيقاف التشغيل مع مسح جميع عمليات النقل واستدعاء رد نداء مثل process.exit() . هل يمكن إضافة شيء مثل هذا إلى وينستون؟

ثم هو log4js-node

أي تحديثات؟ المشكلة حقيقية جدا.

بالنسبة لأي نظام تسجيل ، فإن حساب التفاضل والتكامل هو:

  • إذا كان يجب أن يكون لديك سجلاتك تمامًا وكنت على استعداد لدفع تكلفة أوقات الاستجابة البطيئة ، فاستخدم أداة تسجيل متزامنة
  • إذا كنت تتصل بنفسك بـ process.exit() ، فانتظر حتى يتم مسح الرسائل المخزنة مؤقتًا. بالنسبة إلى winston ، فإن حزمة winston-log-and-exit تفعل ذلك نيابةً عنك.
  • إذا كان هناك رمز آخر يستدعي process.exit() وكان النظام الأساسي الخاص بك به خطاف عند الخروج ، فاستخدم هذا الخطاف وانتظر حتى يتم مسح الرسائل المخزنة مؤقتًا. يمكن أن يساعد winston-log-and-exit في ذلك أيضًا.
  • إذا كنت تستخدم نظامًا أساسيًا مثل AWS Lambda لا يحتوي على خطاف عند الخروج ، فأنت تتداول في مزايا النظام الأساسي مقابل مخاطر فقدان البيانات.

بالمناسبة ، @ begin-again هذه الطريقة 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- رابتور. سيعمل هذا في معظم الأوقات ، لكن ليس مضمونًا أن يعمل طوال الوقت. يحدث فقط أنه تم مسح المخازن المؤقتة الخاصة بك بحلول الوقت الذي تم فيه استدعاء العلامة التالية ، ولكن اعتمادًا على الاتصالات التي يعتمد عليها المسجلون لديك ، فقد يؤدي ذلك بسهولة إلى فقد الرسائل ...

هذا الرمز يعمل معي:

            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 -rite-in-winston

danielweck كلا ، إنه مكسور: # 1629 # 1504!

6 سنوات ، هذا صحيح ، 6 سنوات للخلل الذي تم وضع علامة عليه "هام". إنه خط حدودي مثير للإعجاب.

أستخدم الوعد 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 يجب أن يتم تشغيله فقط بعد أن تتحول حلقة الحدث ، وفي ذلك الوقت سيكون المعالج ملزمًا. أعتقد فقط أن كتابة الكود حيث يكون معالج الأحداث ملزماً أولاً يجعله أكثر وضوحًا.

تضمين التغريدة
أوه ، كيف تربط معالج الحدث بشيء ما؟
سيكون ذلك:

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 () وستكون بخير.

أين رأيت قلت إنني استخدمت مخرج ()؟

آسف لافتراض أن قدرتك على القراءة والفهم كافية لفهم ما يدور حوله هذا الخطأ. تحقق من العنوان مرة أخرى.

يجب أن تكون مشغولاً للغاية إذا واجهت مشكلة كانت مفتوحة لمدة 8 سنوات ولا تقدم أي مساعدة مناسبة على الإطلاق.

لا أفهم كيف لا يفهم الناس أن هذه "المشكلة" لم يتم "حلها" لأنه لا يوجد أي منها. فقط اكتب الكود الصحيح من خلال عدم استدعاء exit () وستكون بخير.

لذا فإن حلنا لهذه المشكلة هو عدم استدعاء process.exit ()؟

نعم ، إنها دائمًا فكرة سيئة في nodejs ، راجع https://stackoverflow.com/a/37592669

حسنًا ، السبب في أنني شخصيًا أستخدم process.exit هو أنني أستمع إلى uncaughtException و unhandledRejection لتسجيل جميع وسائل النقل الخاصة بي ، ثم إنهاء التطبيق. هل هناك طريقة أفضل لإنجاز هذه القضية؟

لم أستخدم وينستون منذ فترة ، لكن ألن يسجل ذلك على أي حال؟ إذا لم يكن الأمر كذلك ، فلن تعمل إعادة طرح الخطأ بعد تسجيله؟

لا أفهم كيف لا يفهم الناس أن هذه "المشكلة" لم يتم "حلها" لأنه لا يوجد أي منها. فقط اكتب الكود الصحيح من خلال عدم استدعاء exit () وستكون بخير.

أين رأيت قلت إنني استخدمت مخرج ()؟

آسف لافتراض أن قدرتك على القراءة والفهم كافية لفهم ما يدور حوله هذا الخطأ. تحقق من العنوان مرة أخرى.

يجب أن تكون مشغولاً للغاية إذا واجهت مشكلة كانت مفتوحة لمدة 8 سنوات ولا تقدم أي مساعدة مناسبة على الإطلاق.

على الأقل يمكنني حل مشاكلي دون أن أنين مثل شقي مؤهل.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات