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到此,我们就能完整的⾃定义请求级别的⽇志了。总结
以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。
因篇幅问题不能全部显示,请点此查看更多更全内容