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 configurationconst 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 exist            filename: 'logs/example.log'        })    ]};const logger = winston.createLogger(logConfiguration);// Log some messageslogger.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 messagelogger.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.jsconst logger = require('./utils/logger');const app = express();const port = 3000;const host = "localhost";// Dummy Express GET callapp.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 errorsapp.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 erorsapp.use((req,res,next) => {    res.status(404).send("PAGE NOT FOUND");    logger.error(`400 || ${res.statusMessage} - ${req.originalUrl} - ${req.method} - ${req.ip}`);})// Run the serverapp.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的原创文章,尽在:"汪子熙":