log4js 升级到 2.x 版本后,原先的 dateFile 不再支持按 category 输出单独文件,需转为 multiFile 形式。但,multiFile 并不支持配置为按 date 输出单独文件。因此,需进行特殊处理。

修改配置如下:

javascriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
appenders: { system: { type: 'multiFile', base: 'logs/', extension: '.log', property: 'logDay', compress: false, maxLogSize: 10485760, backups: 5 } }
appenders: { system: { type: 'multiFile', base: 'logs/', extension: '.log', property: 'logDay', compress: false, maxLogSize: 10485760, backups: 5 } }

然后通过 addContext 设置文件路径和文件名:

javascriptCopy code
  • 1
  • 2
const logger = log4js.getLogger(loggers[key]); logger.addContext('logDay', logger.category + '/' + moment().format('YYYY-MM-DD'));
const logger = log4js.getLogger(loggers[key]); logger.addContext('logDay', logger.category + '/' + moment().format('YYYY-MM-DD'));

但,设置之后,并未随时间变化而生成新的日志文件,即:文件名所取的时间为系统启动的时间,且不再更新(由此可知,同一模块的多次 require 只会执行一次,且,声明的模块变量只进行初始化一次)。即便将时间的取值改为对象或方法动态获取,依然无效。因此,需要寻找一种方法进行动态设置。

So,很自然地想到交由中间件进行处理,即,在所有路由之前,对当前日期进行判断,若有变化,则重新赋值。如下:

javascriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
app.use(function (req, res, next) { updateContext(); …… next(); });
app.use(function (req, res, next) { updateContext(); …… next(); });
javascriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
updateContext: function () { const today = moment().format('YYYY-MM-DD'); if (logDay !== today) { logDay = today; Object.keys(loggers).forEach((key) => { loggers[key].addContext('logDay', loggers[key].category + '/' + logDay); }); } }
updateContext: function () { const today = moment().format('YYYY-MM-DD'); if (logDay !== today) { logDay = today; Object.keys(loggers).forEach((key) => { loggers[key].addContext('logDay', loggers[key].category + '/' + logDay); }); } }

如此,便解决日志信息同时按 category 和 date 分类存储的问题。详细内容,请移步:Follow on GitHub

终结:NestJS 解决方案

上述方案仍存在一些不足,优化后的 NestJS 日志方案请移步:《使用定时任务解决log4js的按日期存储问题》