關(guān)于自定義Egg.js的請求級別日志詳解
Egg.js 是什么?
Egg.js 為企業(yè)級框架和應(yīng)用而生,我們希望由 Egg.js 孕育出更多上層框架,幫助開發(fā)團(tuán)隊和開發(fā)人員降低開發(fā)和維護(hù)成本。
注:Egg.js 縮寫為 Egg
背景
組織為了更好的對各個業(yè)務(wù)的請求日志進(jìn)行統(tǒng)一的分析,制定了統(tǒng)一的日志打印規(guī)范,比如:
[time][processId][traceId][userid] Hello World....
統(tǒng)一格式之后,業(yè)務(wù)現(xiàn)有業(yè)務(wù)的日志工具打印出來的格式是無法滿足該規(guī)范的,所以我們需要對此進(jìn)行改造。
我們前端目前Node中間層使用的框架是Egg.js,所以下文講述下如何在Egg.js上自定義請求日志格式。
開始動手
Egg.js中自帶了三種logger,分別是
- Context Logger
- App Logger
- Agent Logger
Context Logger主要是用來記錄請求相關(guān)的日志。每行日志都會在開頭自動的記錄當(dāng)前請求的一些信息,比如時間、ip、請求url等等。
App Logger用于記錄應(yīng)用級別的日志,比如程序啟動日志。
Agent Logger用于記錄多進(jìn)程模式運行下的日志。
我們想自定義請求級別的日志,那重點就要從Context Logger去研究怎么做。最理想的方案就是,Context Logger本身支持配置化的自定義格式,通過在egg.js的config配置文件中,通過傳入formatter的參數(shù)就能自定義。
//config.default.js
exports.customLogger = {
log: {
file: 'appname.log',
formatter: (message)=>{
return `${message.time}${message.processid}`
}
}
}
但不久我們發(fā)現(xiàn)這條路走不通,設(shè)置了這個formatter并不起作用。從Context Logger的源碼中,我們發(fā)現(xiàn)的端倪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參數(shù)已經(jīng)被內(nèi)部的一個自定義格式化函數(shù)覆蓋了,配置中寫的是不會啟作用的。
此路不通,只能嘗試自己實現(xiàn)logger去解決。自己實現(xiàn)我們需要考慮一些點,比如:
- 日志要寫到文件中,錯誤日志單獨寫一個文件
- 需要能按天或按小時切割日志
- IO性能
如果這些都自己實現(xiàn)的話,那就太麻煩了。好在了解到Egg的這幾個logger都是基于egg-logger和egg-logrotator去實現(xiàn)的,所以我們可以站在巨人的肩膀上搞事情。
Context Logger是基于egg-logger的FileTransport類去進(jìn)行文件落地的,同時FileTransport也默認(rèn)配置了egg-logrotator的日志拆分。所以,我們只需要繼承FileTransport類,實現(xiàn)接口就可以了,代碼如下:
//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')去打印日志,格式則顯示為我們自定義的格式。
到這,自定義日志格式解決了,那我們?nèi)绾潍@取每次請求的信息呢?這里就要借助Egg.js框架對Context的擴(kuò)展功能, Context是請求級別的對象,我們在Context的原型上擴(kuò)展方法可以拿到該對象帶有的每次請求的信息。
//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對象擴(kuò)展
* */
const Logger = require('egg-logger').Logger;
const CoustomTransport = require('./CoustomTransport');
const CustomLogger = require('./CustomLogger');
module.exports = {
get swLog() {
return CustomLogger(this);
}
};
調(diào)用
// app/controller/home.js
module.exports = app => {
class HomeController extends app.Controller {
async index() {
this.ctx.swLog.info('Hello World');
}
}
return HomeController;
};
結(jié)果
[2018-11-02 19:25:09.665][22896][/] Hello World
到此,我們就能完整的自定義請求級別的日志了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
前端JavaScript實現(xiàn)文件壓縮的全面優(yōu)化指南
JavaScript文件大小直接影響網(wǎng)頁加載速度和用戶體驗,本文將詳細(xì)介紹從基礎(chǔ)到高級的各種JavaScript壓縮優(yōu)化技術(shù),小伙伴可以根據(jù)需求進(jìn)行選擇2025-04-04
JavaScript高級程序設(shè)計 閱讀筆記(十九) js表格排序
js表格排序?qū)崿F(xiàn)代碼,需要的朋友可以參考下2012-08-08
TypeScript?Pinia實戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié))
這篇文章主要介紹了TypeScript?Pinia實戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié)),今天我們再來實戰(zhàn)下官方推薦的新的vue狀態(tài)管理工具Pini,感興趣的小伙伴可以參考一下2022-06-06
用js通過url傳參把數(shù)據(jù)從一個頁面?zhèn)鞯搅硪粋€頁面
如果是傳到新頁面的話,你網(wǎng)站基于什么語言開發(fā)直接用get或者post獲取,然后輸出到這個層2014-09-09

