NodeJS winston logger每月旋转文件夹,每天旋转文件

0s7z1bwu  于 2023-08-04  发布在  Node.js
关注(0)|答案(3)|浏览(148)

我的文件夹结构如下

  • 原木
  • 2023-07
  • info-2023-07-20.log
  • info-2023-07-21.log

其中日志是在根目录和使用温斯顿我添加日志到日志文件,文件自动更改使用温斯顿每日旋转文件包,但我也想改变目录时,月份得到的改变这是不工作,我必须重新启动我的服务器,让它工作,否则它只是附加到以前创建的旧文件夹.
下面是我的代码库,我如何设置我的日志。(logger.js)

const fs = require('fs')
const winston = require('winston')
const { format, transports } = winston
const { colorize, combine, timestamp, printf, splat, errors } = format
require('winston-daily-rotate-file')

if (!fs.existsSync('logs/')) {
  fs.mkdirSync('logs/')
}

const todayDate = new Date()
const currentMonth = ('0' + (todayDate.getMonth() + 1)).slice(-2)
const logDir = `logs/${todayDate.getFullYear()}-${currentMonth}` // Directory path for logs.
// month + 1 is because first month starts with 0
if (!fs.existsSync(logDir)) {
  fs.mkdirSync(logDir)
}

const logFormat = combine(
  timestamp({ format: 'HH:mm:ss' }),
  splat(),
  errors({ stack: true }),
  printf(({ timestamp, level, message, stack }) => {
    return `${timestamp},${global.isBackgroundServer ? ` [BG]:` : ''}${
      process.env.NODE_ENV === 'development' ? ` ${level}:` : ''
    } ${typeof message === 'object' ? JSON.stringify(message) : message}${stack ? `, Stack: ${stack}` : ''}`
  }),
)

const defaultLoggerOptions = {
  format: logFormat,
}

const infoTransport = new transports.DailyRotateFile({
  ...defaultLoggerOptions,
  level: 'info',
  filename: logDir + '/Info-%DATE%.log',
})

const errorTransport = new transports.DailyRotateFile({
  ...defaultLoggerOptions,
  level: 'error',
  filename: logDir + '/Error-%DATE%.log',
})

const warningTransport = new transports.DailyRotateFile({
  ...defaultLoggerOptions,
  level: 'debug',
  filename: logDir + '/Warning-%DATE%.log',
})

const consoleTransport = new transports.Console({
  format: combine(colorize(), logFormat),
})

const errorLogger = winston.createLogger({
  transports: [consoleTransport, errorTransport],
})

const successLogger = winston.createLogger({
  transports: [consoleTransport, infoTransport],
})

const warningLogger = winston.createLogger({
  transports: [consoleTransport, warningTransport],
})

const transportConsoleToWinston = () => {
  const getArgumentsStr = (arguments) => {
    return Array.prototype.slice.call(arguments).join(' ')
  }

  const wrappedSuccessLogger = (...args) => successLogger.log.apply(successLogger, ['info', getArgumentsStr(args)])
  const wrappedWarningLogger = (...args) => warningLogger.log.apply(warningLogger, ['warn', getArgumentsStr(args)])
  const wrappedDebugLogger = (...args) => warningLogger.log.apply(warningLogger, ['debug', getArgumentsStr(args)])

  console.log = wrappedSuccessLogger
  console.info = wrappedSuccessLogger
  console.warn = wrappedWarningLogger
  console.debug = wrappedDebugLogger
  console.error = (...args) => errorLogger.error.call(errorLogger, ...args)
}

module.exports = { errorLogger, successLogger, warningLogger, transportConsoleToWinston }

字符串

xmq68pz9

xmq68pz91#

在撰写本文时,您无法在运行时更改dirNamefileName属性。因此,您需要每个月创建一个新的传输,同时每天创建(旋转)一个新文件。我会这么做它依赖于每天自动发生的旋转事件。如果还没有包含当前年份/月份的文件夹,这意味着我们正在更改月份,因此只需创建一个文件夹并更新传输(请参阅评论):

var winston = require('winston');
require('winston-daily-rotate-file');
const fs = require('fs');

// Initialize the transport with the proper folder for the current month.
var transport = new winston.transports.DailyRotateFile({
    dirname:'logs/'+ getDirName(),
    filename: 'log-%DATE%',
    datePattern: 'YYYY-MM-DD', // rotates every day
});

function getDirName(){ // returns current YYYY-MM
    var curDate = new Date();
    var curMonth = ("0" + (curDate.getMonth() + 1)).slice(-2);
    var curYYYYMM = curDate.getFullYear() + "-" + curMonth;
    return curYYYYMM;
}

transport.on('rotate', function (_, _) {
    // Each time there is a file rotation (= every day with this date pattern), if there is not yet
    // a folder with the current name = if the month changed, then create a new transport and
    // set its directory to the new month:
    if (!fs.existsSync('logs/' + getDirName() + '/')) {
        transport = new winston.transports.DailyRotateFile({
            dirname:'logs/'+ getDirName(),
            filename: 'log-%DATE%',
            datePattern: 'YYYY-MM-DD',
        });
    }
});

var logger = winston.createLogger({
    transports: [
        transport
    ]
});

async function demo() {
    while(true) {
        logger.info('Hello World ' + new Date().getSeconds());
        console.log(new Date().getSeconds());
        await new Promise(r => setTimeout(r, 1000));
    }
}

demo();

字符串

hgb9j2n6

hgb9j2n62#

对于这个问题,我有一个简单的想法,我认为值得一试,我们可以使用setTimeout和setInterval来创建logger:

function createLoggers() {
  if (!fs.existsSync('logs/')) {
    fs.mkdirSync('logs/');
  }

  const todayDate = new Date();
  const currentMonth = ('0' + (todayDate.getMonth() + 1)).slice(-2);
  const logDir = `logs/${todayDate.getFullYear()}-${currentMonth}`; // Directory path for logs.

  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir);
  }

  const infoTransport = new transports.DailyRotateFile({
    ...defaultLoggerOptions,
    level: 'info',
    filename: `${logDir}/Info-%DATE%.log`,
  });

  const errorTransport = new transports.DailyRotateFile({
    ...defaultLoggerOptions,
    level: 'error',
    filename: `${logDir}/Error-%DATE%.log`,
  });

// Recreate the logger with a new date at midnight every day. 
setInterval(() => {
  const now = new Date();
  const millisTillMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1) - now;

  setTimeout(() => {
    createLoggers(); //your crate logger logic
  }, millisTillMidnight);
}, 24 * 60 * 60 * 1000);

字符串

gab6jxml

gab6jxml3#

问题

您的代码只为logs文件夹创建一次名称,以后不再更改它。

解决方案

好吧,winston-daily-rotate-file不提供为dirname选项使用占位符的方式,它为filename选项所做的方式,你只能使用完整的日期占位符%DATE%。所以我们每个月都要手动重新创建记录器。以下是许多方法中的一种:

const fs = require('fs')
const winston = require('winston')
const { format, transports } = winston
const { colorize, combine, timestamp, printf, splat, errors } = format
require('winston-daily-rotate-file')

if (!fs.existsSync('logs/')) {
  fs.mkdirSync('logs/')
}

const logFormat = combine(
  timestamp({ format: 'HH:mm:ss' }),
  splat(),
  errors({ stack: true }),
  printf(({ timestamp, level, message, stack }) => {
    return `${timestamp},${global.isBackgroundServer ? ` [BG]:` : ''}${process.env.NODE_ENV === 'development' ? ` ${level}:` : ''
      } ${typeof message === 'object' ? JSON.stringify(message) : message}${stack ? `, Stack: ${stack}` : ''}`
  }),
)

const defaultLoggerOptions = {
  format: logFormat,
}

let errorLogger, successLogger, warningLogger

function createLoggers() {
  const now = new Date()
  const currentMonth = ('0' + (now.getMonth() + 1)).slice(-2)
  const logDir = `logs/${now.getFullYear()}-${currentMonth}` // Directory path for logs.
  // month + 1 is because first month starts with 0
  if (!fs.existsSync(logDir)) {
    fs.mkdirSync(logDir)
  }

  // Lets calculate time left to the begining of the next month and schudule recreation of loggers
  const nextMonth = new Date(now.getFullYear(), now.getMonth()+1, 1)
  setTimeout(createLoggers, nextMonth.getTime() - now.getTime())

  const infoTransport = new transports.DailyRotateFile({
    ...defaultLoggerOptions,
    level: 'info',
    filename: logDir + '/Info-%DATE%.log',
  })

  const errorTransport = new transports.DailyRotateFile({
    ...defaultLoggerOptions,
    level: 'error',
    filename: logDir + '/Error-%DATE%.log',
  })

  const warningTransport = new transports.DailyRotateFile({
    ...defaultLoggerOptions,
    level: 'debug',
    filename: logDir + '/Warning-%DATE%.log',
  })

  const consoleTransport = new transports.Console({
    format: combine(colorize(), logFormat),
  })

  errorLogger = winston.createLogger({
    transports: [consoleTransport, errorTransport],
  })

  successLogger = winston.createLogger({
    transports: [consoleTransport, infoTransport],
  })

  warningLogger = winston.createLogger({
    transports: [consoleTransport, warningTransport],
  })
}

const transportConsoleToWinston = () => {
  const getArgumentsStr = (arguments) => {
    return Array.prototype.slice.call(arguments).join(' ')
  }

  const wrappedSuccessLogger = (...args) => successLogger.log.apply(successLogger, ['info', getArgumentsStr(args)])
  const wrappedWarningLogger = (...args) => warningLogger.log.apply(warningLogger, ['warn', getArgumentsStr(args)])
  const wrappedDebugLogger = (...args) => warningLogger.log.apply(warningLogger, ['debug', getArgumentsStr(args)])

  console.log = wrappedSuccessLogger
  console.info = wrappedSuccessLogger
  console.warn = wrappedWarningLogger
  console.debug = wrappedDebugLogger
  console.error = (...args) => errorLogger.error.call(errorLogger, ...args)
}

module.exports = { errorLogger, successLogger, warningLogger, transportConsoleToWinston }

字符串

说明

代码的大部分被 Package 到createLoggers函数中。准确地说,是负责创建日志功能的更改部分的部分。而且里面还加了一个小块:

// Lets calculate time left to the begining of the next month and schudule recreation of loggers
  const nextMonth = new Date(now.getFullYear(), now.getMonth()+1, 1)
  setTimeout(createLoggers, nextMonth.getTime() - now.getTime())


该块负责计算下个月的开始,并再次调度createLoggers的调用。

可能出现的问题

  • 我没有机会彻底检查这段代码,但也许可以改进它以更精确地检测月初
  • 我不确定这种重新创建记录器的方式是否会导致内存泄漏,但应该不会

相关问题