日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【译】Node.js 日志打印指南

發(fā)布時間:2025/3/15 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【译】Node.js 日志打印指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

當你開始使用JavaScript開發(fā)時,可能要學習的第一個技能就是如何使用console.log將內容打印到控制臺。如果你搜索如何調試JavaScript,將會發(fā)現(xiàn)數(shù)百篇博客和StackOverflow文章指向console.log。因為這是一種很常見的方法,我們甚至開始使用像no-console這樣的linter規(guī)則來確保我們不會在生產代碼中留下意外的日志語句。但是如果我們真的想通過打印一些東西來提供更多的信息呢?

?

在這篇文章中,我們將探討各種需要打印信息的場景;Node.js中console.log和console.error之間有什么區(qū)別;以及如何在不擾亂用戶控制臺的情況下在庫中記錄日志。

console.log(`Let's go!`); 復制代碼

首要理論:Node.js的重要細節(jié)

假如我們能在瀏覽器或者Node.js中使用console.log或console.error,那么在使用Node.js時,有一件重要的事情是要記住的。在一個名為index.js的文件中使用Node.js編寫以下代碼時:

console.log('Hello there'); console.error('Bye bye'); 復制代碼

并在終端使用node index.js執(zhí)行它,你會看到它們并排輸出了:

?

?

?

然而,盡管這兩者看起來相同,但實際上系統(tǒng)對它們的處理是不同的。查看Node.js文檔關于console的介紹,我們可以看到,console.log輸出到stdout,console.error輸出到stderr

每個進程默認有三個可以使用的流:stdin, stdout和stderr。stdin流處理進入程序的輸入。例如,按鈕按下或重定向輸出(我們稍后會講到)。stdout流用于應用程序的輸出。最后,stderr用于錯誤消息。如果你想了解為什么存在stderr以及何時使用它,請參閱這篇文章。

簡而言之,我們可以使用重定向(>)和管道(|)操作符將應用程序的錯誤和診斷信息結果分離顯示。>操作符允許我們將stdout的輸出重定向到文件中,而2>允許我們將stderr的輸出重定向到文件中。例如,這個命令將“Hello there”導入一個名為Hello.log的文件,并將“Bye Bye”導入一個名為error.log的文件。

node index.js > hello.log 2> error.log 復制代碼

?

?

?

什么情況下我們需要log?

既然我們已經了解了一些關于日志的底層技術方面的知識,那么接下來讓我們來討論一下可能需要記錄日志的場景。通常這些場景包含以下類別:

  • 開發(fā)過程中快速調試異常
  • 基于瀏覽器的日志記錄,用于分析或診斷
  • 記錄服務應用日志,以記錄傳入的請求以及可能發(fā)生的任何故障
  • 庫的可選調試日志,以協(xié)助用戶排查問題
  • 通過CLI打印進度、確認信息或錯誤

下面的內容我們將跳過的前兩個場景,重點介紹跟Node.js有關的后面三個場景。

服務應用日志

在服務器上記錄日志的原因可能有很多。例如,通過記錄傳入的請求我們可以用來做信息統(tǒng)計,比如用戶遇到有多少404請求,這些請求可能是什么,或者正在使用什么User-Agent。我們也想知道什么時候出了問題,原因是什么。

如果你想嘗試本文下面內容,請創(chuàng)建一個新的項目目錄。在項目目錄中創(chuàng)建index.js用于編寫代碼的程序運行入口。運行以下代碼初始化項目并安裝express:

npm init -y npm install express 復制代碼

讓我們設置一個帶有console.log的中間件的服務器。將以下內容放入index.js文件中:

const express = require('express');const PORT = process.env.PORT || 3000; const app = express();app.use((req, res, next) => {console.log('%O', req);next(); });app.get('/', (req, res) => {res.send('Hello World'); });app.listen(PORT, () => {console.log('Server running on port %d', PORT); }); 復制代碼

我們使用console.log('$0',req)用于記錄整個對象。console.log底層使用util.format方法支持%O占位符。詳細信息可以在Node.js官方文檔中了解。

當執(zhí)行node index.js來執(zhí)行服務器并訪問http://localhost:3000時,你會注意到它將打印出許多我們并不真正需要的信息。

?

?

?

即使我們將其更改為console.log('%s', req)不打印整個對象,也不會得到太多有用的信息。

?

?

?

我們可以寫我們自己的log函數(shù),只輸出我們關心的東西。但是在此之前,我們先討論下通常需要關心什么。雖然太多信息分散我們注意力的集中,但實際上我們也需要充分的信息。如:

  • 時間戳——知道事情發(fā)生的時間
  • 計算機/服務器名稱——如果你正在運行一個分布式系統(tǒng)
  • 進程ID——如果你正在使用類似pm2的東西運行多個節(jié)點進程
  • 消息——包含一些內容的實際消息
  • 堆棧跟蹤——用于記錄錯誤的場景
  • 其他一些額外的變量/信息

此外,既然我們已經知道所有內容都將進入stdout和stderr流,那么我們可以借助它們實現(xiàn)不同級別的日志,以及根據(jù)它們配置和篩選日志的能力。

我們可以通過訪問進程的各個部分并編寫一堆JavaScript來實現(xiàn)所有這些功能,但Node.js最棒的一點是,擁有npm生態(tài)系統(tǒng),而且已經有各種庫可供我們使用。例如:

  • pino
  • winston
  • roarr
  • bunyan (注意:這個已經兩年沒有更新了)

我個人喜歡pino,因為它速度快,生態(tài)也很好。讓我們看看如何使用pino幫助我們進行日志記錄。奇妙的是已經有一個express-pino-logger包,我們可以使用它來記錄請求。

安裝pino和express-pino-logger:

npm install pino express-pino-logger 復制代碼

然后更新index.js文件,使用日志記錄器和中間件:

const express = require('express'); const pino = require('pino'); const expressPino = require('express-pino-logger');const logger = pino({ level: process.env.LOG_LEVEL || 'info' }); const expressLogger = expressPino({ logger });const PORT = process.env.PORT || 3000; const app = express();app.use(expressLogger);app.get('/', (req, res) => {logger.debug('Calling res.send');res.send('Hello World'); });app.listen(PORT, () => {logger.info('Server running on port %d', PORT); }); 復制代碼

在這個代碼片段中,我們創(chuàng)建了一個pino的日志程序實例,并將其傳遞到express-pino-logger中來創(chuàng)建一個新的日志程序中間件以便app.use調用。此外,我們在服務啟動的時候用logger.info替換console.log,并向路由添加了一個額外的logger.debug,以顯示不同級別的日志。

如果通過再次運行node index.js啟動服務器。你會看到一個非常不同的輸出,它每一行輸出一個JSON。再次訪問http://localhost:3000,你將看到添加了一行新的JSON。

?

?

?

如果檢查這個JSON,你將看到它包含前面提到的所有信息,比如時間戳。你還可能注意到我們的logger.debug語句沒有打印出來。這是因為我們使用了默認的日志級別。創(chuàng)建logger實例時,我們通過設置process.env.LOG_LEVEL的值改變日志級別,默認值為info。通過運行LOG_LEVEL=debug node index.js,我們可以調整日志級別顯示debug類型的日志。

在此之前,讓我們先討論這樣一個事實:現(xiàn)在的輸出實際上可讀性很差。然而這是故意的。pino遵循一種原則,即更高的性能。我們也可以通過管道(使用|)將所有進程的日志移動到一個單獨的進程中,用于提高其可讀性或將數(shù)據(jù)上載到云服務器。這個過程叫做transports。查看關于transports的文檔,還可以了解為什么pino中的錯誤沒有被寫入stderr。

讓我們使用工具pino-pretty查看更具可讀性的日志版本。在終端執(zhí)行一下命令:

npm install --save-dev pino-pretty LOG_LEVEL=debug node index.js | ./node_modules/.bin/pino-pretty 復制代碼

現(xiàn)在,使用|操作符,所有的日志將通過管道傳輸?shù)絧ino-pretty,你的輸出應該變得清晰,包含了關鍵信息并且被著色。再次訪問http://localhost:3000,還應該能看到debug級別的消息。

?

?

?

有許多現(xiàn)成的傳輸工具可以美化或轉換日志。你甚至可以用pino-colada工具使其支持表情符號的顯示。這些將對你本地的開發(fā)非常有用。在生產環(huán)境中運行服務器之后,你可能希望將日志導入到另一個傳輸中,使用>將日志寫入磁盤,以便稍后處理它們,或者使用tee之類的命令進行處理。

官方文檔還介紹關于日志文件歸檔、過濾和將日志寫入不同文件等內容。

你的庫日志

既然我們已經了解了如何為服務器應用程序高效地編寫日志,為什么不為我們編寫的庫使用相同的技術呢?

問題是,我們希望打印出庫用于調試的內容,但也不能混淆使用者的應用程序。如果需要調試某些東西,使用者應該能夠啟用日志。你的庫在默認情況下應該是靜默的,并將是否打印日志留給使用者決定。

express就是一個很好的例子。express的底層做了很多事情,在調試應用程序時,你可能想了解一下底層的情況。如果我們查閱express文檔,便會注意到啟動相關日志只需要在命令前加上DEBUG=express:*:

DEBUG=express:* node index.js 復制代碼

使用現(xiàn)有的應用程序運行該命令,你將看到許多額外的輸出,這些輸出將幫助你調試問題。

?

?

?

如果沒有啟用調試日志記錄,就不會看到這些。這是是通過一個名為debug的包來實現(xiàn)的。它允許我們在指定“名稱空間”下編寫消息,如果庫的使用者在調試環(huán)境變量中包含與之匹配的名稱空間或通配符,它將輸出這些消息。

要使用debug庫,首先安裝它:

npm install debug 復制代碼

讓我們通過創(chuàng)建一個新文件來嘗試它,該文件將模擬我們的庫random-id.js,并在其中放置以下代碼:

const debug = require('debug');const log = debug('mylib:randomid');log('Library loaded');function getRandomId() {log('Computing random ID');const outcome = Math.random().toString(36).substr(2);log('Random ID is "%s"', outcome);return outcome; }module.exports = { getRandomId }; 復制代碼

以上代碼創(chuàng)建一個名稱空間為mylib:randomid的新調試日志實例,其打印了兩條消息。讓我們在上一章的index.js中使用它:

const express = require('express'); const pino = require('pino'); const expressPino = require('express-pino-logger');const randomId = require('./random-id');const logger = pino({ level: process.env.LOG_LEVEL || 'info' }); const expressLogger = expressPino({ logger });const PORT = process.env.PORT || 3000; const app = express();app.use(expressLogger);app.get('/', (req, res) => {logger.debug('Calling res.send');const id = randomId.getRandomId();res.send(`Hello World [${id}]`); });app.listen(PORT, () => {logger.info('Server running on port %d', PORT); }); 復制代碼

重新運行服務器,但是這次使用DEBUG=mylib:randomid node index.js,它將打印我們的“庫”的調試日志。

?

?

?

有趣的是,如果你的庫使用者希望將此調試信息放入他們的pino日志中,他們可以使用pino團隊提供的pino-debug庫來正確格式化這些日志。

使用以下方法安裝庫:

npm install pino-debug 復制代碼

在第一次使用debug之前,需要初始化pino-debug。最簡單的方法是在啟動腳本之前使用Node.js的-r或——require標志來引入模塊。使用如下命令重新運行服務器(假設已經安裝了pino-colada):

DEBUG=mylib:randomid node -r pino-debug index.js | ./node_modules/.bin/pino-colada 復制代碼

現(xiàn)在,你將看到庫的調試日志與應用程序日志的格式相同。

?

?

?

CLI(命令行界面)輸出

在這篇文章中,我們將討論的最后一種情況是CLIs而不是庫的特殊日志記錄情況。我的原則是將邏輯日志與CLI輸出的“日志”分開。對于任何邏輯日志,都應該使用debug之類的庫。這樣,你或其他人就可以重用邏輯,而不受CLI特定用例的限制。

當你的Node.js應用采用CLI構建時,你可能希望通過添加顏色、標記或以一種特定的具有視覺吸引力的方式格式化內容,使其看起來更漂亮。然而,在使用CLI構建時,你應該記住以下幾個場景。

一種場景是,你的CLI可能在持續(xù)集成(CI)系統(tǒng)的上下文中使用,因此你可能希望刪除顏色或任何花哨的裝飾輸出。一些CI系統(tǒng)設置了一個稱為CI的環(huán)境標志。如果你想更安全地檢查你是否在CI中,可以使用is-CI這樣的包,它已經支持許多CI系統(tǒng)。

一些庫,如chalk,已經為你檢測是否CI環(huán)境并為你刪除顏色。接下來讓我們一起看下使用它之后的樣子。

使用npm安裝chalk并創(chuàng)建一個名為clip .js的文件。放入以下代碼:

const chalk = require('chalk'); console.log('%s Hi there',chalk.cyan('INFO')); 復制代碼

現(xiàn)在,如果你使用node clip.js運行這個腳本,你將看到彩色的輸出。

?

?

?

但是如果你用CI=true node clip .js運行它,你會看到顏色被抑制了:

?

?

?

你要記住的另一個場景是,如果你的stdout運行在終端模式中,表示內容寫入終端。如果是這種情況,我們可以使用boxen之類的東西來顯示所有漂亮的輸出。如果不是,很可能輸出被重定向到文件或管道的某個地方。

你可以通過檢查相應流上的isTTY屬性來檢查stdin、stdout或stderr是否處于終端模式,例如:process.stdout.isTTY。TTY代表“teletypewriter(電傳打字機)”,在本例中特指終端。

根據(jù)Node.js進程的啟動方式,這三個流的值可能有所不同。你可以在Node.js文檔的“process I/O”部分了解更多。

讓我們看看process.stdout的值。isTTY在不同的情況下是不同的。更新你的clil.js文件,以檢查它:

const chalk = require('chalk'); console.log (process.stdout.isTTY); console.log('%s Hi there',chalk.cyan('INFO')); 復制代碼

現(xiàn)在在你的終端中運行node clip.js,你會看到true后面跟著我們的彩色消息。

?

?

?

之后運行相同的東西,但重定向輸出到一個文件,并檢查內容后運行:

node clip .js > output.log cat output.log 復制代碼

你將看到,這一次它打印的是undefined,后面跟著一條純色的消息,因為stdout的重定向關閉了stdout的終端模式。chalk使用了support-color檢查相應流上是否支持TTY。

?

?

?

類似chalk這樣的工具已經為你處理了這種場景。但是,在開發(fā)CLI時,你應該始終了解CLI可能在CI模式下運行或重定向輸出的情況。它還可以幫助您進一步獲得CLI的體驗。例如,你可以在終端中以漂亮的方式排列數(shù)據(jù),如果isTTY未定義,則切換到更容易解析的方式。

總結

開始使用JavaScript并使用console.log記錄第一行代碼非常快,但是當你將代碼投入生產時,你應該考慮更多關于日志的內容。這篇文章僅僅介紹了各種方法和可用的日志解決方案。但它不包含你需要知道的一切。我建議你查看一些你最感興趣的開源項目,了解它們如何解決日志記錄問題以及使用哪些工具。現(xiàn)在去記錄所有的信息,而不是僅僅打印日志吧😉。

原文:A Guide to Node.js Logging

?

總結

以上是生活随笔為你收集整理的【译】Node.js 日志打印指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。