簡體   English   中英

如何在node.js中使用stack trace記錄錯誤?

[英]How to console.log an error with stack trace in node.js?

我一直在嘗試調試我的節點應用程序,以便在我的日志中找到錯誤的來源,該錯誤僅顯示為“ Error: Can't set headers after they are sent ”,沒有跟蹤信息或任何上下文。

碰巧,我想我現在已經解決了這個問題...我正在使用connect-timeout並且我正在繼續處理傳遞給異步網絡操作的回調,盡管回調最終會嘗試執行res.send() ,盡管在網絡操作期間, connect-timeout req.timedout設置為“true”。

但我仍然無法理解為什么我的日志沒有顯示此錯誤的跟蹤信息。 在我的代碼中返回錯誤的任何地方我將其記錄到控制台:

console.log(err);

如果err對象中有可用的跟蹤信息,並且這似乎放在err.stack ,那么上述語句是否應該將err (包括err.stack )的全部內容轉儲到控制台日志中? 我的理解是,通過上述操作,我不會丟失任何信息,例如:

console.log(err.stack);

但是像這樣的帖子似乎暗示了其他情況(雖然鏈接的帖子現在已經更新)。

我實際上更進一步,並添加一些相關的文本,以幫助找到錯誤:

console.log('error in dodgyFunction:', err);

但盡管如此,我仍然只得到“ Error: Can't set headers after they are sent ”,沒有任何上下文我會說。 這是因為此控制台錯誤消息是在外部庫(如express )中輸出的嗎? 我認為外部庫應該將錯誤發送回主代碼進行相應的處理?

編輯:這是我將錯誤和超時檢查放在傳遞給異步操作的回調函數頂部的示例:

var execFile = require('child_process').execFile;
execFile('dodgycommand', options, function(error, stdout, stderr) {
    if (req.timedout) {
        console.log('timeout detected whilst running dodgycommand, so aborting...');
        return;
    }
    if (error) {
        console.log('error running dodgycommand:', error);
        res.sendStatus(400);
        return;
    }

    // ... it's safe to continue ...

}

我基本上都遵循相同的模式。

我剛剛弄清楚發生了什么,我希望這會幫助其他人避免這個初學者的錯誤。

對於我的一些錯誤記錄,我使用類似下面的內容,使用字符串連接來構造錯誤消息:

console.log('error in function abc: ' + err + ' whilst doing xyz');

而在其他地方,我使用類似下面的內容,只是將錯誤消息的各個部分作為單獨的參數傳遞給console.log

console.log('error in function xyz:', err, 'whilst doing abc');

我現在看到這些給出了不同的結果!

前者必須將err字符串化,以便它可以與消息的其他部分連接,並且根據這一點 ,這樣做它只使用消息部分。

但是,在后一種形式中, err對象必須由console.log處理,並且作為一個整體進行轉儲。

這就解釋了為什么我有時沒有看到錯誤的全部內容,正如我所期待的那樣,有時我也是如此。

對於由其他庫放置的控制台日志消息,要檢查的其他內容是您沒有過濾掉日志查看器中日志消息的“堆棧”部分...原來我 (為了節省日志配額......我正在使用papertrail)... d'oh。 我這樣做是通過過濾掉以____at開頭的任何行(四個空格后跟'at'),例如____at Request.self.callback

你的模式看起來很普遍,不過我會說通常我不喜歡它,更多的是在一秒鍾內。

至於你的主要問題,根據你提供的內容很難回答它。 如果您顯示實際代碼而不是“我通常遵循此模式”,它可能會有所幫助。 但同樣可能的是,錯誤被拋出到你沒想到的地方,所以你的console.log根本沒有被調用。

看起來你正在尋找最佳實踐,所以我會告訴你我認為迄今為止我發現的最好的東西。

首先,不要使用console.log進行日志記錄。 這並不可怕,但你可以做得更好,更好。 我最喜歡的是使用morgan作為中間件來記錄請求信息,並調試應用程序日志記錄。

通過debug您可以設置自定義日志級別,並以您想要的任何粒度級別收聽您想要的任何級別。 它都是通過設置DEBUG環境變量來控制的,在生產中你可以重定向到文件或你想要的任何其他目的地。 此外,許多節點模塊(包括Express和Connect)使用Debug作為其記錄器,因此通過調整DEBUG變量,您可以根據需要查看內部日志記錄的多少。 對於弄清楚哪里出了問題非常有用。

其次,正如我所說,在路由方面,我根本不使用你所擁有的模式。 如果我不小心的話,我發現很容易意外地多次發送標題,所以我的中間件總是返回next()並且響應只在實際的處理程序中發送,我只能確保只觸發一次。 當涉及到錯誤時,我總是傳遞next(e) ,然后我可以在錯誤處理函數中處理它。 我還創建了praeter庫,以根據Web狀態代碼和通用錯誤處理程序提供標准錯誤。

模式看起來像這樣:

// middleware function to put something on the request object
app.use((req, res, next) => {
  MyModel.doSomething((e, thing) => {
    if (e) return next(e);
    if (!thing) return next(new NotFound()); // NotFound is an error in praeter that equates to a 404. 
    req.thing = thing;
    return next();
  });
});

然后

// log in here is a reference to my debug configured log object
app.use((err, req, res, next) => {
  log.error(err);
  log.error(err.stack);
  return res.status(err.statusCode || 500).send(err.message)
});

請注意,這是最終錯誤處理程序的簡單示例。 我經常有幾個這樣的地方,根據應用需求,我可能會以不同的方式處理不同的錯誤代碼。

我現在安裝了n ,我可以確認以下內容:

節點4.0.0

使用console.log(err)僅打印錯誤消息。

節點7.7.0 (最新)

使用console.log(err)打印錯誤消息和完整堆棧。


我已經確認在6.0.0版本上此行為已更改。 因此,如果您使用舊版本,我建議您更新Node.js或使用console.log(err.stack)來打印完整堆棧。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM