2013-07-17 25 views
8

我在node.js中開發一個RESTful服務器,使用Express作爲框架,目前Winston作爲記錄器模塊。 該服務器將處理大量的同時請求,並且使用諸如「請求ID」之類的東西來跟蹤每個特定請求的日誌條目對我來說非常有用。直接的解決方案就是在每次我想創建日誌條目時添加此ID作爲另一條日誌信息,但這意味着要將「請求ID」傳遞給服務器使用的每個方法。如何通過Express中的中間件鏈來識別請求(通過ID)。

我想知道是否有任何node.js/javascript模塊或技術,可以讓我以一種更簡單的方式做到這一點,而無需攜帶每個特定請求的請求ID。

回答

4

您可以使用req對象來確認每個請求都附帶了express。
所以,你會在你的應用程序做的第一路徑將是:

var logIdIterator = 0; 

app.all('*', function(req, res, next) { 
    req.log = { 
    id: ++logIdIterator 
    } 
    return next(); 
}); 

然後內快遞的任何地方,你可以訪問idreq對象:req.log.id;
您仍然需要將一些數據傳遞到需要創建某些日誌的函數中。實際上,您可能在req.log對象內具有日誌記錄功能,這樣可以保證只有在訪問對象時纔會進行日誌記錄。

+1

謝謝你的回答。我也會使用你提出的解決方案。但是,我想要自動識別要應用的ID。我實現的解決方案是將ID存儲在請求對象中,並且在調用我的自定義日誌函數時,它會在callstack中查找ID。我知道這是錯誤的幾個原因(在嚴格模式下訪問其他函數的參數信息是被禁止的,效率不高,並且在I/O事件被觸發時獲得新的堆棧)。 我想這是不可能的,你提出的解決方案似乎是最適合的解決方案。 –

16

如果您自動遞增,您的後續日誌分析將無法唯一標識請求,因爲不同的實例會生成衝突的ID,並且重新啓動應用程序將自動導致ID衝突。

這是另一種可能的解決方案。

安裝CUID:

npm install --save cuid 

然後在你的主應用程序文件:

var cuid = require('cuid'); 
var requestId = function requestId(req, res, next) { 
    req.requestId = cuid(); 
    next(); 
}; 

// Then, at the top of your middleware: 
app.use(requestId); 

現在你會得到這樣的局面不可能碰撞友好的請求ID,你就可以唯一標識您對日誌分析和調試的請求,即使在多個實例中也是如此,並且服務器重新啓動。

+1

是的,這肯定是更好的解決方案,但問題在於如何在winston日誌中公開id,以便不會造成太多數據重複。 –

+0

我也會使用域名(或者他們決定用它來替換域名的任何內容),所以你不會通過在你的代碼層中傳遞請求信息來污染函數調用。 – CBP

+0

域名已被棄用,並且沒有具體的替代計劃。 –

0

你不應該使用全局變量。

我喜歡做的是在每個請求之前填充一個META對象。

我使用UUID發生器(https://github.com/kelektiv/node-uuid)到ID的請求

下面是一個例子

app.all('*', function(req, res, next) { 
    req.meta = { 
     ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress, 
     timestamp: uuid(), 
     user_agent: req.headers['user-agent'], 
     body: req.body, 
    } 
    return next(); 
    }) 
2

我掙扎搜索針對此問題的解決方案。 我不喜歡它關於這裏提出的解決方案的事情是,它們意味着分享項目中所有功能中的req對象。 我發現了一種混合你的方法(創建每個請求的uuid)和一個允許在模塊之間共享名稱空間的庫(continuation-local-storage)的解決方案。

你可以找到在這個其他答案的解釋:https://stackoverflow.com/a/47261545/5710581

如果您想了解更多的信息,我寫下這些想法和所有的代碼在後,爲了在一個地方來說明一切: Express.js: Logging info with global unique request ID – Node.js