您的当前位置:首页正文

关于自定义Egg.js的请求级别日志详解

2023-10-21 来源:易榕旅网
关于⾃定义Egg.js的请求级别⽇志详解

Egg.js 是什么?

Egg.js 为企业级框架和应⽤⽽⽣,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发⼈员降低开发和维护成本。注:Egg.js 缩写为 Egg背景

组织为了更好的对各个业务的请求⽇志进⾏统⼀的分析,制定了统⼀的⽇志打印规范,⽐如:

[time][processId][traceId][userid] Hello World....

统⼀格式之后,业务现有业务的⽇志⼯具打印出来的格式是⽆法满⾜该规范的,所以我们需要对此进⾏改造。我们前端⽬前Node中间层使⽤的框架是Egg.js,所以下⽂讲述下如何在Egg.js上⾃定义请求⽇志格式。开始动⼿

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

Context LoggerApp LoggerAgent 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的源码中,我们发现的端倪

[ '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-logger和egg-logrotator去实现的,所以我们可以站在巨⼈的肩膀上搞事情。

Context Logger是基于egg-logger的FileTransport类去进⾏⽂件落地的,同时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;

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

到这,⾃定义⽇志格式解决了,那我们如何获取每次请求的信息呢?这⾥就要借助Egg.js框架对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.jsmodule.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到此,我们就能完整的⾃定义请求级别的⽇志了。总结

以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。

因篇幅问题不能全部显示,请点此查看更多更全内容