天天看點

Node 進階:express 預設日志元件 morgan 從入門使用到源碼剖析

morgan是express預設的日志中間件,也可以脫離express,作為node.js的日志元件單獨使用。本文由淺入深,内容主要包括:

morgan使用入門例子

如何将日志儲存到本地檔案

核心api使用說明及例子

進階使用:1、日志分割 2、将日志寫入資料庫

源碼剖析:morgan的日志格式以及預編譯

首先,初始化項目。

然後,在<code>basic.js</code>中添加如下代碼。

morgan支援stream配置項,可以通過它來實作将日志落地的效果,代碼如下:

morgan的api非常少,使用頻率最高的就是<code>morgan()</code>,作用是傳回一個express日志中間件。

參數說明如下:

options:可選,配置項,包含<code>stream(常用)</code>、<code>skip</code>、<code>immediate</code>。

stream:日志的輸出流配置,預設是<code>process.stdout</code>。

immediate:布爾值,預設是false。當為true時,一收到請求,就記錄日志;如果為false,則在請求傳回後,再記錄日志。

首先搞清楚morgan中的兩個概念:format 跟 token。非常簡單:

format:日志格式,本質是代表日志格式的字元串,比如 <code>:method :url :status :res[content-length] - :response-time ms</code>。

token:format的組成部分,比如上面的<code>:method</code>、<code>:url</code>即使所謂的token。

搞清楚format、token的差別後,就可以看下morgan中,關于自定義日志格式的關鍵api。

非常簡單,首先通過<code>morgan.format()</code>定義名為<code>joke</code>的日志格式,然後通過<code>morgan('joke')</code>調用即可。

我們來看下運作結果

代碼如下,通過<code>morgan.token()</code>自定義token,然後将自定義的token,加入自定義的format中即可。

一個線上應用,如果所有的日志都落地到同一個本地檔案,時間久了,檔案會變得非常大,既影響性能,又不便于檢視。這時候,就需要用到日志分割了。

借助<code>file-stream-rotator</code>插件,可以輕松完成日志分割的工作。除了<code>file-stream-rotator</code>相關的配置代碼,其餘跟之前的例子差不多,這裡不贅述。

有的時候,我們會有這樣的需求,将通路日志寫入資料庫。這種需求常見于需要實時查詢統計的日志系統。

在morgan裡該如何實作呢?從文檔上,并沒有看到适合的擴充接口。于是查閱了下<code>morgan</code>的源碼,發現實作起來非常簡單。

回顧下之前日志寫入本地檔案的例子,最關鍵的兩行代碼如下。通過<code>stream</code>指定日志的輸出流。

在<code>morgan</code>内部,大緻實作是這樣的(簡化後)。

于是,可以用比較取巧的方式來實作目的:聲明一個帶<code>write</code>方法的對象,并作為<code>stream</code>配置傳入。

morgan的代碼非常簡潔,從設計上來說,morgan的生命周期包含:

token定義 --&gt; 日志格式定義 -&gt; 日志格式預編譯 --&gt; 請求達到/傳回 --&gt; 寫日志

其中,token定義、日志格式定義前面已經講到,這裡就隻講下 日志格式預編譯 的細節。

跟模闆引擎預編譯一樣,日志格式預編譯,也是為了提升性能。源碼如下,最關鍵的代碼就是<code>compile(fmt)</code>。

<code>compile()</code>方法的實作細節這裡不贅述,着重看下<code>compile(fmt)</code>傳回的内容:

運作上面程式,輸出内容如下,其中<code>tokens</code>其實就是<code>morgan</code>。

看下<code>morgan.token()</code>的定義,就很清晰了