自定义Egg.js的请求级别日志

栏目: JavaScript · 发布时间: 6年前

内容简介:组织为了更好的对各个业务的请求日志进行统一的分析,制定了统一的日志打印规范,比如:统一格式之后,业务现有业务的日志工具打印出来的格式是无法满足该规范的,所以我们需要对此进行改造。我们前端目前Node中间层使用的框架是Egg.js,所以下文讲述下如何在Egg.js上自定义请求日志格式。

组织为了更好的对各个业务的请求日志进行统一的分析,制定了统一的日志打印规范,比如:

[time][processId][traceId][userid] Hello World....
复制代码

统一格式之后,业务现有业务的日志 工具 打印出来的格式是无法满足该规范的,所以我们需要对此进行改造。

我们前端目前Node中间层使用的框架是Egg.js,所以下文讲述下如何在Egg.js上自定义请求日志格式。

开始动手

Egg.js中自带了三种logger,分别是

  • Context Logger
  • App Logger
  • Agent Logger

Context Logger主要是用来记录请求相关的日志。每行日志都会在开头自动的记录当前请求的一些信息,比如时间、ip、请求url等等。

App Logger用于记录应用级别的日志,比如程序启动日志。

Agent Logger用于记录多进程模式运行下的日志。

我们想自定义请求级别的日志,那重点就要从 Context Logger 去研究怎么做。最理想的方案就是, Context Logger 本身支持配置化的自定义格式,通过在egg.js的config配置文件中,通过传入formatter的参数就能自定义。

//config.default.js
exports.customLogger = {
    log: {
        file: 'appname.log',
        formatter: (message)=>{
            return `${message.time}${message.processid}` 
        }
    }
}
复制代码

但不久我们发现这条路走不通,设置了这个formatter并不起作用。从Context Logger的源码中,我们发现的端倪 context_logger.js

[ 'error', 'warn', 'info', 'debug' ].forEach(level => {
  const LEVEL = level.toUpperCase();
  ContextLogger.prototype[level] = function() {
    const meta = {
      formatter: contextFormatter,
      paddingMessage: this.paddingMessage,
    };
    this._logger.log(LEVEL, arguments, meta);
  };
});

module.exports = ContextLogger;

function contextFormatter(meta) {
  return meta.date + ' ' + meta.level + ' ' + meta.pid + ' ' + meta.paddingMessage + ' ' + meta.message;
}
复制代码

在源码中我们可以看到,formatter参数已经被内部的一个自定义格式化函数覆盖了,配置中写的是不会启作用的。

此路不通,只能尝试自己实现logger去解决。自己实现我们需要考虑一些点,比如:

  • 日志要写到文件中,错误日志单独写一个文件
  • 需要能按天或按小时切割日志
  • IO性能

如果这些都自己实现的话,那就太麻烦了。好在了解到Egg的这几个logger都是基于 egg-loggeregg-logrotator 去实现的,所以我们可以站在巨人的肩膀上搞事情。

Context Logger 是基于 egg-loggerFileTransport 类去进行文件落地的,同时 FileTransport 也默认配置了 egg-logrotator 的日志拆分。所以,我们只需要继承 FileTransport 类,实现接口就可以了,代码如下:

//CoustomTransport.js
const FileTransport = require('egg-logger').FileTransport;
const moment = require('moment');

class CoustomTransport extends FileTransport {
    constructor(options, ctx) {
        super(options);
        this.ctx = ctx;
    }

    log(level, args, meta) {
        const prefixStr = this.buildFormat(level);
        for (let i in args) {
            if (args.hasOwnProperty(i)) {
                if (parseInt(i, 10) === 0) {
                    args[i] = `${prefixStr}${args[i]}`;
                }
                if (parseInt(i, 10) === args.length - 1) {
                    args[i] += '\n';
                }
            }
        }

        super.log(level, args, meta);
    }

    buildFormat(level) {
        const timeStr = `[${moment().format('YYYY-MM-DD HH:mm:ss.SSS')}]`;
        const threadNameStr = `[${process.pid}]`;
        const urlStr = `[${this.ctx.request.url}]`
        return `${timeStr}${threadNameStr}${urlStr}`;
    }

    setUserId(userId) {
        this.userId = userId;
    }
}

module.exports = CoustomTransport;
复制代码

实现CoustomTransport类后,我们就可以初始化logger

//CustomLogger.js
const Logger = require('egg-logger').Logger;
const CoustomTransport = require('./CoustomTransport.js');
const logger = new Logger();
logger.set('file', new CoustomTransport({
    level: 'INFO',
    file: 'app.log'
}));

module.exports = logger;
复制代码

我们通过logger.info('Hello World')去打印日志,格式则显示为我们自定义的格式。

到这,自定义日志格式解决了,那我们如何获取每次请求的信息呢?这里就要借助Egg.js框架对Context的扩展功能, Context是请求级别的对象,我们在Context的原型上扩展方法可以拿到该对象带有的每次请求的信息。

//CustomLogger.js
const Logger = require('egg-logger').Logger;
const CoustomTransport = require('./CoustomTransport.js');

module.exports = function(ctx){
    const logger = new Logger();
    logger.set('file', new CoustomTransport({
        level: 'INFO',
        file: 'app.log'
    }, ctx));
    return logger;
};

// app/extend/context.js
/*
* Context对象扩展
* */
const Logger = require('egg-logger').Logger;
const CoustomTransport = require('./CoustomTransport');
const CustomLogger = require('./CustomLogger');
module.exports = {
    get swLog() {
        return CustomLogger(this);
    }
};

复制代码

调用

// app/controller/home.js
module.exports = app => {
    class HomeController extends app.Controller {
        async index() {
            this.ctx.swLog.info('Hello World');
        }
    }
    return HomeController;
};
复制代码

结果

[2018-11-02 19:25:09.665][22896][/] Hello World
复制代码

到此,我们就能完整的自定义请求级别的日志了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Tagging

Tagging

Gene Smith / New Riders / 2007-12-27 / GBP 28.99

Tagging is fast becoming one of the primary ways people organize and manage digital information. Tagging complements traditional organizational tools like folders and search on users desktops as well ......一起来看看 《Tagging》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具