如何在进程退出前强制nodejs winston log到文件

zphenhs4  于 2023-06-22  发布在  Node.js
关注(0)|答案(5)|浏览(130)

我正在使用winston 3记录我的数据。但有时它在进程退出之前没有记录错误。
以下进程将退出,不记录到logfile.log

const winston = require('winston');

winston.add(new winston.transports.File({
    filename: 'logfile.log'
}));

winston.info('please log me in');
process.exit(1);

尝试的解决方案之一是使用回调:

const winston = require('winston');

const logger = new winston.createLogger({
    new winston.transports.File({
    filename: 'logfile.log'
}));

winston.info('please log me in', () => {
    process.exit(1);
});

setTimeout(() => {}, 100000000000); // pause the process until process.exit is call

但是Winston 3.x有callback issue,所以上面的代码不会工作,进程不会退出。
我正在寻找一个可行的解决方案。任何帮助将不胜感激。我的操作系统是Ubuntu 16.04Node 10.17

**编辑1:**我也试过Prabhjot Singh Kainth的建议,用finish事件触发进程退出:

const winston = require('winston');

const logger = winston.createLogger({
    transports: [
        new winston.transports.File({
            filename: 'logfile.log'
        })
    ]
});

logger.info('please log me in');

logger.on('finish', () => {
    process.exit();
});
logger.end();

setTimeout(() => {}, 100000000000); // pause the process until process.exit is call

在上述情况下,进程将退出,但不会创建日志文件。

8qgya5xd

8qgya5xd1#

这个怎么样?

logger.info('First message...')
logger.info('Last message', () => process.exit(1))
jv4diomz

jv4diomz2#

最后,我找到了一个可行的解决方案。而不是监听loggerfinish事件,它应该监听file._destfinish事件。但是file._dest仅在fileopen事件之后创建。因此在初始化过程中需要等待fileopen事件。

const winston = require('winston');

const file = new winston.transports.File({
  filename: 'logfile.log'
});

const logger = winston.createLogger({
    transports: [file]
});

file.on('open', () => {  // wait until file._dest is ready
  logger.info('please log me in');
  logger.error('logging error message');
  logger.warn('logging warning message');

  file._dest.on('finish', () => {
    process.exit();
  });
  logger.end();
});

setTimeout(() => {}, 100000000000); // pause the process until process.exit is call
fcwjkofz

fcwjkofz3#

每个winston.Logger示例也是一个Node.js流。
当流结束后所有日志都刷新到所有传输时,将引发完成事件。
试着使用这个代码:

const transport = new winston.transports.Console();
const logger = winston.createLogger({
  transports: [transport]
});
logger.on('finish', function (info) {
  // All `info` log messages has now been logged
});

logger.info('CHILL WINSTON!', { seriously: true });
logger.end();
2jcobegt

2jcobegt4#

answer from @WanChap很好,但在有多个文件传输的情况下就不行了。我将在下面发布我的整个日志解决方案,它可以正确处理退出流程,包括对开发和生产的支持。
唯一的警告是,它目前不适用于异常日志,但它将适用于所有其他基于传输的日志。如果有人知道如何使用异常日志,请在评论中发表。
首先,您希望在执行日志的文件所在的目录中创建一个文件夹,并将其命名为logger。在此文件夹中创建三个.js文件,一个名为**dev-logger.js,另一个名为prod-logger.js,最后是index.js**
在node中,当你需要一个目录时,它会假设你要加载**index.js文件。**

TheFileYouWantToLogFrom.js

const logger = require('./logger');
logger.info("it works!");

index.js

该文件将查看节点进程环境状态并使用正确的日志记录器。

const buildDevLogger = require('./dev-logger');
const buildProdLogger = require('./prod-logger');

let logger = null;
if(process.env.NODE_ENV === 'development'){
    logger = buildDevLogger();
}else{
    logger = buildProdLogger();
}

module.exports = logger;

您可以稍后测试它,只需在终端中调用节点进程(在我的示例中是cron.js),比如说NODE_ENV=production node cron.jsNODE_ENV=development node cron.js

dev-logger.js

const { format, createLogger, transports} = require('winston');
const { timestamp, combine, printf, errors } = format;

var numOpenTransports = 0;

function buildDevLogger(){
    const logFormat = printf(({ level, message, timestamp, stack, durationMs }) => {
        return `${timestamp} ${level}: ${stack || message}${durationMs ? " | "+durationMs+'ms' : ''}`;
    });
    
    //For info on the options go here.
    //https://github.com/winstonjs/winston/blob/master/docs/transports.md
    var options = {
        console: {
            handleExceptions: true,
            level: 'debug',
            format: combine(
                format.colorize(),
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                logFormat
            ),
        },
        combined: {
            filename: 'logs/dev/combined.log',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                logFormat
            ),
        },
        error: { 
            filename: 'logs/dev/error.log',
            level: 'error',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true ,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                logFormat
            ),
        },
        exception : {
            filename: 'logs/dev/exceptions.log',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                logFormat
            ),
        }
    };

    function fileFinished(){
        numOpenTransports--;
        if(numOpenTransports==0){
            process.exit(0);
        }
    }

    var combinedFile = new transports.File(options.combined);
    var errorFile = new transports.File(options.error);
    var exceptionFile = new transports.File(options.exception);

    combinedFile.on('open', () => {  // wait until file._dest is ready
        numOpenTransports++;
        combinedFile._dest.on('finish', () => {
            fileFinished();
        });
    });
    errorFile.on('open', () => {  // wait until file._dest is ready
        numOpenTransports++;
        errorFile._dest.on('finish', () => {
            fileFinished();
        });
    });

    return createLogger({
        defaultMeta: {service:'cron-dev'},
        transports: [
            new transports.Console(options.console),
            combinedFile, 
            errorFile,
        ],
        exceptionHandlers: [
            exceptionFile
        ]
    });
}

module.exports = buildDevLogger;

prod-logger.js

const { format, createLogger, transports} = require('winston');
const { timestamp, combine, errors, json } = format;

var numOpenTransports = 0;

function buildProdLogger(){
    var options = {
        console: {
            handleExceptions: true,
            level: 'debug',
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                json()
            ),
        },
        combined: {
            filename: 'logs/prod/combined.log',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                json()
            ),
        },
        error: { 
            filename: 'logs/prod/error.log',
            level: 'error',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true ,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                json()
            ),
        },
        exception : {
            filename: 'logs/prod/exceptions.log',
            maxsize: 10000000,
            maxFiles: 10,
            tailable:true,
            format: combine(
                timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
                errors({stack: true}),
                json()
            ),
        }  
    };

    function fileFinished(){
        numOpenTransports--;
        if(numOpenTransports==0){
            process.exit(0);
        }
    }

    var combinedFile = new transports.File(options.combined);
    var errorFile = new transports.File(options.error);
    var exceptionFile = new transports.File(options.exception);

    combinedFile.on('open', () => {  // wait until file._dest is ready
        numOpenTransports++;
        combinedFile._dest.on('finish', () => {
            fileFinished();
        });
    });
    errorFile.on('open', () => {  // wait until file._dest is ready
        numOpenTransports++;
        errorFile._dest.on('finish', () => {
            fileFinished();
        });
    });

    return createLogger({
        defaultMeta: {service:'cron-prod'},
        transports: [
            new transports.Console(options.console),
            combinedFile, 
            errorFile,
        ],
        exceptionHandlers: [
            exceptionFile
        ]
    });
}

module.exports = buildProdLogger;

dev和prod logger文件的工作方式是使用numOpenTransports变量来跟踪当前打开的“文件传输”,一旦它们都关闭,* 然后 *,然后退出进程

n3schb8v

n3schb8v5#

我尝试了下面的代码,但总是得到“TypeError:file.on不是函数”。我用的是Winston 3.9.0版本。

const winston = require('winston');

const file = new winston.transports.File({
  filename: 'logfile.log'
});

const logger = winston.createLogger({
    transports: [file]
});

file.on('open', () => {  // wait until file._dest is ready
  logger.info('please log me in');
  logger.error('logging error message');
  logger.warn('logging warning message');

  file._dest.on('finish', () => {
    process.exit();
  });
  logger.end();
});

setTimeout(() => {}, 100000000000); // pause the process until process.exit is call

相关问题