关于⾃定义Egg.js的请求级别⽇志详解
Egg.js 是什么?
Egg.js 为企业级框架和应⽤⽽⽣,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发⼈员降低开发和维护成本。
注:Egg.js 缩写为 Egg
背景
组织为了更好的对各个业务的请求⽇志进⾏统⼀的分析,制定了统⼀的⽇志打印规范,⽐如:
[time][processId][traceId][userid]
统⼀格式之后,业务现有业务的⽇志⼯具打印出来的格式是⽆法满⾜该规范的,所以我们需要对此进⾏改造。
我们前端⽬前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的源码中,我们发现的端倪
[ 'error', 'warn', 'info', 'debug' ].forEach(level => {
const LEVEL = UpperCase();
ContextLogger.prototype[level] = function() {
const meta = {
formatter: contextFormatter,
paddingMessage: this.paddingMessage,
};
this._logger.log(LEVEL, arguments, meta);
};
});
js argumentsfunction contextFormatter(meta) {
return meta.date + ' ' + meta.level + ' ' + meta.pid + ' ' + meta.paddingMessage + ' ' + ssage;
}
在源码中我们可以看到,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);
< = 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 = `[${quest.url}]`
return `${timeStr}${threadNameStr}${urlStr}`;
}
setUserId(userId) {
this.userId = userId;
}
}
我们通过 logger.info('Hello World')去打印⽇志,格式则显⽰为我们⾃定义的格式。
到这,⾃定义⽇志格式解决了,那我们如何获取每次请求的信息呢?这⾥就要借助Egg.js框架对Context的扩展功能, Context 是请求级别的对象,我们在的原型上扩展⽅法可以拿到该对象带有的每次请求的信息。
//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'
}, ctx));
return logger;
};
// app/extend/context.js
/*
* Context对象扩展
* */
const Logger = require('egg-logger').Logger;
const CoustomTransport = require('./CoustomTransport');
const CustomLogger = require('./CustomLogger');
get swLog() {
return CustomLogger(this);
}
};
调⽤
// app/controller/home.js
class HomeController extends app.Controller {
async index() {
}
}
return HomeController;
};
结果
[2018-11-02 19:25:09.665][22896][/] Hello World
到此,我们就能完整的⾃定义请求级别的⽇志了。
总结
以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论