先前曾总结了2篇文章(见:《log4js按分类和日期存储为多文件问题》《使用定时任务解决log4js的按日期存储问题》)描述如何解决log4js的按日期存储问题,然而,通过日志可以发现,前述方案虽然解决了操作日志的按日期存储问题,却并没有解决通过log4js.connectLogger中间件方式产生的访问日志的按日期存储问题。

即,下述代码产生的访问日志并没有按日期分开存储:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
app.use( log4js.connectLogger(logger, { level: LogLevel.INFO, format: (req, res, format) => { return format( ':remote-addr - :method :status HTTP/:http-version :url - [:response-time ms/:content-length B] ":referrer" ":user-agent"' ); } }) );
app.use( log4js.connectLogger(logger, { level: LogLevel.INFO, format: (req, res, format) => { return format( ':remote-addr - :method :status HTTP/:http-version :url - [:response-time ms/:content-length B] ":referrer" ":user-agent"' ); } }) );

查看该中间件的源码可以发现,前述方案的定时任务中每日更新的context并没有对其生效,也即,访问日志仍是在系统启动时的context中。因此,解决方案似乎也很清晰了,将logger对象改为动态获取。如下:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
getAccessLogger(updateContext = false) { const logger = this.loggers[LoggerName.ACCESS]; if (updateContext) { logger.clearContext(); logger.addContext(this.loggerContextKey, moment().format('YYYY-MM-DD')); } return logger; }
getAccessLogger(updateContext = false) { const logger = this.loggers[LoggerName.ACCESS]; if (updateContext) { logger.clearContext(); logger.addContext(this.loggerContextKey, moment().format('YYYY-MM-DD')); } return logger; }

然而,事实证明,还是想得太简单了,该方法仍然无效。由此可见,对于通过app.use方式使用的中间件,仅被“实例化”一次,系统启动后,不会再更新。

因此,需要另想办法……

一个很自然的想法是,为何不直接采用Nest.js方式的中间件呢?于是,有了下述方案: