关于 Node.js 应用里使用 winston 进行日志记录的最佳实践
Logging with Winston and Node.js
假設您有一個在生產環境中運行的應用程序,每天有數百萬用戶賺取數千美元。應用程序可能存在錯誤的原因有多種,作為開發人員,您需要找出原因并修復它。沒有人愿意使用有問題的應用程序,修復錯誤會花費時間和金錢。
你怎么能解決這個問題?也許通過回到代碼并檢查每一行代碼是否按預期運行。這對于小型應用程序來說更容易,但即便如此,嘗試觸發與用戶相同類型的錯誤也可能很困難。想象一下,這在大型應用程序中會有多難。
假設有一個實例,應用程序收集一些用戶的信息并將它們保存到數據庫中。
如果應用程序失敗,服務器將向最終用戶返回系統錯誤。最好能捕獲這些實例并解決這些錯誤。在這種情況下,您如何知道用戶 a 或用戶 b 遇到了單個系統錯誤?這些錯誤可能由代碼中的錯誤、損壞的文件、錯誤的邏輯或數據類型不匹配觸發。
如果你需要避免這種挫折,你就無法避免日志記錄。日志是程序員首先要查找的地方,用于跟蹤錯誤和事件流,尤其是來自服務器的事件。日志會告訴您當應用程序運行并與用戶交互時會發生什么。日志記錄的一個很好的用例是,例如,如果您的系統中有一個錯誤,并且您想了解導致其發生的步驟。
日志記錄是將應用程序活動生成的信息記錄到日志文件中的過程。保存在日志文件中的消息稱為日志。日志是記錄在日志文件中的單個實例。
在 Node.js 中構建應用程序日志至關重要。在本地運行應用程序時,可以將其掛接到調試器上,非常棒,可以在運行應用程序時發現問題。在開發過程中,您通常會使用 console.log 來獲取應用程序日志。
但是當一個應用程序投入生產并且用戶開始與之交互時,你就不能再使用 console.log 了。如果出現問題并且應用程序崩潰,則無法使用控制臺進行檢查。如果你有一個簡潔、干凈和高質量的日志中間件,比如 Winston,那會很有幫助。
Winston 處理您的應用程序活動并將有用的信息生成到日志文件或數據庫中。之后,您可以檢查應用程序生成的所有活動。
本指南將在 Winston 的上下文中解釋日志記錄。
了解生產應用程序是否出現問題的唯一方法是創建日志。 記錄重新創建并為您保存該問題。 如果出現問題或出現問題,日志會告訴您。
了解系統的行為方式。 日志記錄將生成有關系統如何與用戶交互以及進出系統的信息。
跟蹤您的系統活動。 日志可以顯示實例發生的時間以及觸發日志的原因。
通常,日志記錄的臨界值是:
- 錯誤跟蹤
- 調試
- 應用性能
選擇 winston 的收益
Winston 是最好的日志中間件之一,每周下載量約為 4,000,000 次。以下屬性使 Winston 成為整體通用的日志記錄中間件。
- 它使用簡單且可配置。
- 日志級別(優先級)。 Winston 提供日志記錄級別。它們表示日志優先級;這使您能夠從需要較少關注的日志中整理出關鍵日志。例如:{錯誤:0,警告:1,信息:2,詳細:3,調試:4,傻:5}。在這種情況下,錯誤日志的優先級高于詳細日志。
- 記錄通道(傳輸)。一個好的記錄器有不同的方式來選擇你的日志輸出目的地。使用 Winston,您可以以不同方式發送和保存日志,例如文件、數據庫、電子郵件和控制臺。
- 日志格式。 Winston 為您提供了多種日志格式。例如,在將日志保存到 Mongo 數據庫時,日志格式需要為 JSON 格式。
- 日志分析。 Winston 可幫助您分析代碼塊并測量成功執行代碼所需的時間。
Winston transporters
Winston 的特性之一是它支持各種傳輸,例如文件傳輸。 這會將生成的日志消息保存到日志文件中。 該文件是在您的系統中指定的。 如果應用程序創建了它的第一個日志實例,該文件將自動生成。 之后,任何日志都將保存到創建的文件中。
為此,記錄器配置對象需要指向一個文件(文件傳輸器)。 只需將新 winston.transports.File 中的傳輸配置對象 .transports.Console() 替換為 .transports.File() 即可,如下所示。
transports.File({filename: 'logs/example.log' })這指定生成的任何日志都將保存在日志文件夾下的 example.log 文件中。
傳輸配置將是:
// Logger configuration const logConfiguration = {'transports': [new winston.transports.File({filename: 'logs/example.log'})] };log 文件的內容:
Winston 允許您實現多個日志傳輸,即可以將日志記錄到文件、控制臺或數據庫中。
下面的 Logger 配置記錄到控制臺和文件。 我們將向日志配置對象添加一個傳輸數組。 在本指南的后面,我們將向您展示如何將日志實例記錄到數據庫中。
const logConfiguration = {transports: [new winston.transports.Console({level: 'warn'}),new winston.transports.File({level: 'error',// Create the log directory if it does not existfilename: 'logs/example.log'})] };const logger = winston.createLogger(logConfiguration);// Log some messages logger.error("Hello, Winston logger, the first error!"); logger.warn("Hello, Winston logger, the first warning!"); logger.warn("Hello, Winston logger, the second warning!"); logger.error("Hello, Winston logger, the second error!"); logger.info("Hello, Winston logger, some info!"); logger.debug("Hello, Winston logger, a debug!");這規定:
- 日志將顯示在控制臺輸出中。
- 只有屬于錯誤級別的日志才會記錄在 example.log 文件中。
使用 Winston,您可以指定保存日志的默認格式。
例如,假設我們想以 JSON 格式登錄,我們可以使用 Winston.format 指定,并且日志實例將以 JSON 格式保存。
format: winston.format( )該格式采用其他日志表單屬性,例如
- ms() - 自記錄上次日志以來的時間(以毫秒為單位)。
- label() - 向記錄的消息添加標簽。
- timestamp() - 收到日志消息的時間戳。
- splat() - 提供字符串插值。
要將其應用到您的日志中,您需要使用 format.combine,如下例所示。
const logConfiguration = {transports: [new winston.transports.Console()],format: winston.format.combine(winston.format.label({label: `Label🏷?`}),winston.format.timestamp({format: 'MMM-DD-YYYY HH:mm:ss'}),winston.format.printf(info => `${info.level}: ${info.label}: ${[info.timestamp]}: ${info.message}`),) };const logger = winston.createLogger(logConfiguration);// Log a message logger.info("Hello, Winston logger, some info!");輸出:
info: Label🏷?: Nov-18-2020 08:10:44: Hello, Winston logger, some info!
Configuring Winston with a server
讓我們創建一個簡單的 Express 服務器,我們可以使用 Winston 進行一些日志記錄。 這將是一個小項目,可以讓您使用 Winston 記錄來自服務器請求和響應的日志。
繼續使用 npm install express 安裝 Express 庫。
這是我們小項目的結構:
- Logs - 將保存由 Winston 文件傳輸生成的日志文件。
- app.js - 將成為我們的服務器應用程序。
- Utils - 將保存 Winston logger.js,我們將在其中添加 Winston 傳輸和格式等配置。
Logger.js:
const { createLogger, format, transports } = require('winston');module.exports = createLogger({ transports:new transports.File({filename: 'logs/server.log',format:format.combine(format.timestamp({format: 'MMM-DD-YYYY HH:mm:ss'}),format.align(),format.printf(info => `${info.level}: ${[info.timestamp]}: ${info.message}`),)}), });app.js:
const express = require('express');// Require logger.js const logger = require('./utils/logger'); const app = express(); const port = 3000; const host = "localhost";// Dummy Express GET call app.get('/',(req,res) => {res.send("Hello World!");logger.info("Server Sent A Hello World!"); })// Introduce error by using undefined variable 'y' app.get('/calc',(req,res) => {const x = y + 10;res.send(x.toString()); })// Capture 500 errors app.use((err,req,res,next) => { res.status(500).send('Could not perform the calculation!');logger.error(`${err.status || 500} - ${res.statusMessage} - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`); })// Capture 404 erors app.use((req,res,next) => {res.status(404).send("PAGE NOT FOUND");logger.error(`400 || ${res.statusMessage} - ${req.originalUrl} - ${req.method} - ${req.ip}`); }) // Run the server app.listen(port, () => {console.log("Server started...");logger.info(`Server started and running on http://${host}:${port}`) })每次服務器啟動時,Winston 都會將日志記錄到 server.log 文件中。
服務器運行時,訪問以下頁面會在每次調用鏈接時創建日志。
http://localhost:3000/ - 服務器將發送一條 hello world 消息。 我們希望 Winston 捕獲它并將其記錄在我們的日志文件中。
http://localhost:3000/calc - 我們試圖將變量 y 添加到變量 x。 在這種情況下,未定義變量 y。 這將產生一個錯誤,我們希望 Winston 為我們捕獲這個實例。
http://localhost:3000/hello - 我們創建的服務器沒有這樣的 URL。 我們希望 Winston 在指向我們 IP 地址的鏈接被訪問但無法找到時通知我們; 那是 404 錯誤。
output:
info: Nov-12-2020 10:07:59: Server started and running on http://localhost:3000
info: Nov-12-2020 10:08:02: Server Sent A Hello World!
error: Nov-12-2020 10:08:05: 500 - Internal Server Error - y is not defined - /calc - GET - ::1
error: Nov-12-2020 10:08:10: 400 || Not Found - /hello - GET - ::1
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的关于 Node.js 应用里使用 winston 进行日志记录的最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LOLS10石像鬼日女怎么玩?日女玩法技
- 下一篇: winston log 库如何创建 cu