日志系统

在本小节的正式内容之前,我们先来闲聊一下目前市面上的日志框架。在笔者为lin-cms实现日志系统的过程中,浏览和使用了诸多的日志框架,诸如javalog4jlogbacknode.jslog4jegg-logger以及consola,还有其它很多的日志框架。

不难发现,java作为工业界的王者,它的日志框架最为齐全,高效和易用,因此node.jslog4j几乎可以说是大量借鉴了javalog4j。得益于log4j优雅的设计哲学,nodejs 的log4j目前已经是nodejs下的第一日志框架,可惜因为js本身的桎梏,nodejs 版的 log4j 不够灵活。

lin-cms-koa日志系统拥有自己的标准,这个日志标准需要高度的自定制。因此,笔者确实纠结了很长一段时间,koa这个框架过小,基础设施太少,因此必须得去集成其它框架,nodejs的生态虽然说很不错,可惜质量跟java比确实显得相形见绌。

很可惜,log4j不能够满足我们的要求,consola输出的日志确实很漂亮,可以仅仅支持终端的普通输出。因此笔者选择了egg-logger进行定制,笔者在实现的过程中,仿佛可以体会到egg.js团队可能也不满log4j,所以实现了自己的egg-logger

闲聊完了,接下来正式进入日志系统的内容。

使用

lin-cms-koa中,日志系统是开箱即用的,你无需自己去集成,可以直接拿来就用。它被挂载到了context的原型上,你可以通过如下的方式主动调用。

  1. ctx.logger.info();
  2. ctx.logger.warn();
  3. ctx.logger.debug();
  4. ctx.logger.error();

请将重要的调试信息输出到日志中,方便开发查看。

日志记录

lin-cms-koa记录的日志会默认记录到两个地方:

  • 终端:将日志记录到终端是最基础的记录方法,几乎所有的库都会向终端输出日志。

  • 文件:将日志记录到文件,绝大部分情况我们需要将日志存储到磁盘以供后面查看和分析。lin-cms-koa 记录到文件的日志,是有一套标准的,如下:

  1. logs
  2. └── 2019-06
  3. ├── 2019-06-12.log
  4. ├── 2019-06-14.log
  5. └── 2019-06-17.log

日志文件默认存储到当前工作目录下的logs目录,且每一个月都是一个子目录,每一个子目录下皆有每一天的日志文件。当某一个日志文件超过一定的大小时,会被切割。

具体日志的记录信息如下:

  1. 2019-06-16 21:32:59,857 DEBUG 8110 --- [7insummer] - [POST] -> [/cms/file/] from: 127.0.0.1 costs: 39ms data:{
  2. "param": {},
  3. "body": {}
  4. }
  5. 2019-06-16 21:33:37,748 DEBUG 8110 --- [7insummer] - [POST] -> [/cms/user/login] from: 127.0.0.1 costs: 7ms data:{
  6. "param": {},
  7. "body": {
  8. "nickname": "super",
  9. "password": "123456"
  10. }
  11. }

日志配置

app/config/log.js下存放着日志系统的配置:

  1. module.exports = {
  2. log: {
  3. level: 'DEBUG', // 日志记录的level,推荐开发环境下为DEBUG,生产环境下为INFO
  4. dir: 'logs', // 记录日志文件的目录,默认为logs
  5. sizeLimit: 1024 * 1024 * 5, // 日志文件的切割大小,默认为5M
  6. requestLog: true, // 记录http请求日志,默认为true,即记录,为false时则不记录
  7. file: true // 是否开启日志文件记录,默认为true
  8. }
  9. };

在上面,已经明确的标明了每一项配置的作用,不过我们还是需要着重强调两个地方。

  • level,日志的 level 很重要,只要 level 足够的日志才会被输出,一般开发环境下推荐 debug,生产环境下推荐 info。

  • file,磁盘 IO 是耗性能的。所以日志记录到文件是有成本的,如果你追求极致的性能,又对日志的记录的要求不高,确实可以考虑关闭 file。

自定义 Transport

Transport(传输),是egg-logger里面一个重要的概念,你可以把它简单的理解为日志传输。记住,日志是可以有多条传输的,默认lin-cms-koa有两条传输路径consolefile。你可以自定义一条Transport并加入到logger中,让日志传输到你需要传输到的地方。

  1. // urllib-transport.js
  2. const urllib = require('urllib');
  3. const Transport = require('egg-logger').Transport;
  4. class UrllibTransport extends Transport {
  5. log(level, args, meta) {
  6. const msg = super.log(level, args, meta);
  7. return urllib.request('url?msg=' + msg);
  8. }
  9. }
  1. // app.js
  2. app.context.logger.set(
  3. 'remote',
  4. new UrllibTransport({
  5. level: 'DEBUG'
  6. })
  7. );
  8. logger.info('info');

如上,我们自定义了一个UrllibTransport的类,并将其加到了logger中,这样日志就可以通过urllib发送到其它地方。