如何在进程退出之前强制nodejs winston日志记录到文件
How to force nodejs winston log to file before process exit
我正在使用 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
但是Winston3.x有callback issue,所以上面的代码不行,进程不会退出。
我正在寻找可行的解决方案?任何帮助将不胜感激。我的OS是Ubuntu16.04,节点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
在上述情况下,进程将退出,但不会创建日志文件。
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();
终于,我找到了一个可行的解决方案。而不是监听 logger
finish
事件,它应该监听 file._dest
finish
事件。但是 file._dest
仅在 file
open
事件之后创建。所以在初始化过程中需要等待file
open
事件
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
这个怎么样?
logger.info('First message...')
logger.info('Last message', () => process.exit(1))
很好,但当存在 多个文件传输时 就不行了。我将在下面 post 我的整个日志记录解决方案,它可以正确处理退出进程,包括对开发和生产的支持。
仅 需要注意的是,它目前不适用于异常日志,但它可以与所有其他基于传输的日志一起使用。如果有人知道如何使异常日志也能正常工作,请在评论中 post。
首先,您要在执行日志的文件所在的同一目录中创建一个文件夹,并将其命名为 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.js
或 NODE_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 记录器文件的工作方式是使用 numOpenTransports
变量来跟踪当前打开的 'files transports',一旦它们全部关闭,然后,仅然后,退出进程。
我正在使用 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
但是Winston3.x有callback issue,所以上面的代码不行,进程不会退出。
我正在寻找可行的解决方案?任何帮助将不胜感激。我的OS是Ubuntu16.04,节点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
在上述情况下,进程将退出,但不会创建日志文件。
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();
终于,我找到了一个可行的解决方案。而不是监听 logger
finish
事件,它应该监听 file._dest
finish
事件。但是 file._dest
仅在 file
open
事件之后创建。所以在初始化过程中需要等待file
open
事件
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
这个怎么样?
logger.info('First message...')
logger.info('Last message', () => process.exit(1))
仅 需要注意的是,它目前不适用于异常日志,但它可以与所有其他基于传输的日志一起使用。如果有人知道如何使异常日志也能正常工作,请在评论中 post。
首先,您要在执行日志的文件所在的同一目录中创建一个文件夹,并将其命名为 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.js
或 NODE_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 记录器文件的工作方式是使用 numOpenTransports
变量来跟踪当前打开的 'files transports',一旦它们全部关闭,然后,仅然后,退出进程。