這篇文章主要給大家介紹了關於Nodejs中獲取當前函數被調用的行數及文件名的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧
背景
在自定義Egg.js的請求級別日誌這篇文章中,我們實現了自定義請求級別的日誌模塊。看上去功能是完整了,但好像還缺點什麼。
大家在根據日誌追查問題的過程中,很多時候看到了某條log信息想去找出處,但是實際上代碼裏面打相同類型的log地方可能不止一處,這時你就比較難去定位這行log到底是哪裏打的。
舉個最極端的例子
//home.js class AppController extends app.Controller { async first() { this.ctx.swLog.info('in controller'); await this.ctx.render('first.html'); } async second(){ this.ctx.swLog.info('in controller') await this.ctx.render('second.html'); } }
上面的例子雖然比較極端,但是我們在代碼中難免會碰到類似的情況。兩個route對於的controller中都打印了相同的log,你在查日誌的時候,是無法區分log到底是first裏面打的還是second裏面打的。
這個時候,我們就需要在日誌打印的時候,同時也將調用日誌時的文件名和代碼行數記錄下來一併打印,效果如下
[2018-11-02 19:25:09.665][22896][home.js:4][/] in controller
開始動手
查了很久的Nodejs文檔,發現Nodejs的api中並沒有直接提供我們想到的信息,所以只能另找出路。
回憶我們以往的開發,這類的信息好像只有在Nodejs拋出異常的時候看到過。每當Nodejs拋出異常時,我們都能看到一堆異常調用的堆棧,裏面就有我們想要的信息,我們從這開始入手。
我們先手動創造一個異常對象,並打印出來
function getException() { try { throw Error(''); } catch (err) { return err; } } let err = getException(); console.log(err);
console的信息如下圖:
在圖上我們可以看到,我們想要的信息
err對象在console的時候,會直接輸出err對象中的stack屬性,該屬性是個字符串,我們可以通過一系列的字符串操作,拿到我們想要的文件名和行數。
接下來我們開始對日誌模塊代碼進行改造,新增一個getCallerFileNameAndLine方法,如下:
getCallerFileNameAndLine(){ function getException() { try { throw Error(''); } catch (err) { return err; } } const err = getException(); const stack = err.stack; const stackArr = stack.split('\n'); let callerLogIndex = 0; for (let i = 0; i < stackArr.length; i++) { if (stackArr[i].indexOf('Map.Logger') > 0 && i + 1 < stackArr.length) { callerLogIndex = i + 1; break; } } if (callerLogIndex !== 0) { const callerStackLine = stackArr[callerLogIndex]; return `[${callerStackLine.substring(callerStackLine.lastIndexOf(path.sep) + 1, callerStackLine.lastIndexOf(':'))}]`; } else { return '[-]'; } }
最終結果
最後我們每條打印的日誌後面,都會跟上文件名和行數
有的同學可能擔心,每次打log都拋一個異常,會不會對性能造成影響。
我在getCallerFileNameAndLine方法前後進行打點統計,平均執行時間在2ms左右,所以是可以忽略不計的。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對神馬文庫的支持。