您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關如何自定義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 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-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是請求級別的對象,我們在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
感謝各位的閱讀!關于“如何自定義Egg.js的請求級別日志”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。