等哪天需要引入日志组件来代替console.log的时候,才发现恶梦开始了。
遇到这种情况有没有什么好的办法呢,本文提供一个思路:将console.log这些方法重写。
以winston日志组件为例:
const util = require('node:util') function formatArgs(func){ return function (...theArgs) { const formatString = theArgs[0] const args = theArgs.slice(1) func?.(util.format(formatString, ...args)) } } // logger 为 winston实例 function bindToConsole(logger){ console.log = formatArgs(logger.info.bind(logger)) console.error = formatArgs(logger.error.bind(logger)) console.info = formatArgs(logger.info.bind(logger)) }这样就达到了重写console方法的目的,bindToConsole(logger)之后的代码中的console.log, console.error, console.info都会调用winston logger中相应的方法进行日志打印或保存。其它日志组件也可以参考此方法。
附完整代码:
const util = require('node:util') const winston = require('winston') const DailyRotateFile = require('winston-daily-rotate-file') const _createLogger = winston.createLogger const format = winston.format const transports = winston.transports const customFormat = format.combine( format.timestamp({format: 'YYYY-MM-DD HH:mm:ss'}), format.align(), format.printf((i) => `${i.level}: [${i.timestamp}]: ${i.message}`) ) const defaultOptions = { format: customFormat, datePattern: "YYYY-MM-DD", zippedArchive: true, maxSize: "20m", maxFiles: "90d" } function formatArgs(func){ return function (...theArgs) { const formatString = theArgs[0] const args = theArgs.slice(1) func?.(util.format(formatString, ...args)) } } function bindToConsole(logger){ console.log = formatArgs(logger.info.bind(logger)) console.error = formatArgs(logger.error.bind(logger)) console.info = formatArgs(logger.info.bind(logger)) } function createLogger(dir){ const logger = _createLogger({ format: customFormat, transports: [ new transports.Console(), new DailyRotateFile({ filename: dir+"/%DATE%.log", level: "info", ...defaultOptions }), new transports.File({ filename: "logs/error.log", level: "error" }) ] }) bindToConsole(logger) return logger } module.exports = { createLogger }