JavaScript로 개발을 시작할 때 가장 먼저 배우는 것은 console.log를 사용하여 콘텐츠를 콘솔에 기록하는 방법입니다. JavaScript를 디버깅하는 방법을 검색하면 console.log를 사용하라고 알려주는 수백 개의 블로그 게시물과 StackOverflow 기사를 찾을 수 있습니다. 이는 매우 일반적인 관행이기 때문에 코드에 no-console과 같은 linter 규칙을 사용하여 예상치 못한 로그 메시지가 남지 않도록 보장합니다. 하지만 정말로 무언가를 녹음하고 싶다면 어떻게 해야 할까요? console.log 将内容记录到控制台。如果你去搜索如何调试 JavaScript,会发现数百篇博文和 StackOverflow 文章都会简单的告诉你用 console.log。因为这是一种很常见的做法,我们甚至会在代码中使用像 no-console 这样的 linter 规则来确保不会留下意外的日志信息。但是如果我们真的想要去记录某些内容呢? 在本文中,我们将梳理各种情况下要记录的日志信息,Node.js 中 console.log 和console.error之间的区别是什么,以及如何在不发生混乱的情况下把你库中的日志记录输出到用户控制台。 【视频教程推荐:nodejs视频教程 】console.log(`Let's go!`);理论先行:Node.js 的重要细节 虽然你可以在浏览器和 Node.js 中使用 console.log 或 console.error,但在使用 Node.js 时要记住一件重要的事。当你在 Node.js 中将以下代码写入名为 index.js 的文件中时:console.log('Hello there'); console.error('Bye bye');并用 node index.js이 글에서는 다양한 상황에서 기록되는 로그 정보를 정리해보겠습니다. Node.js의 console.log와 console.error의 차이점은 무엇인가요? , 혼란을 일으키지 않고 라이브러리에서 사용자 콘솔로 로깅을 출력하는 방법을 설명합니다. 【동영상 튜토리얼 추천: nodejs 동영상 튜토리얼 】 node index.js > hello.log 2> error.log 이론 우선: Node.js의 중요한 세부 사항 브라우저와 Node.js에서 console.log 또는 console.error이지만 Node.js를 사용할 때 기억해야 할 중요한 사항이 하나 있습니다. Node.js에서 index.js라는 파일에 다음 코드를 작성하고 console部分,会看到 console.log 是输出到 stdout 而 console .error 用的是 stderr。 每个进程都有三个可用的默认 stream。那些是 stdin,stdout 和 stderr。 stdin 流用来在处理进程的输入。例如按下按钮或重定向输出。 stdout 流用于程序的输出。最后 stderr 用于错误消息。如果你想了解为什么会有 stderr 存在,以及应该在什么时候使用它,可以查看这篇文章。 简而言之,这允许我们在 shell 中使用重定向(>)和管道(|)来处理错误和诊断信息,它们是与程序的实际输出结果是分开的。虽然 > 允许我们将命令的输出重定向到文件中,但是 2> 允许我们将 stderr 的输出重定向到文件中。例如,下面这个命令会将 “Hello there” 传给一个名为 hello.log 的文件并把 “Bye bye” 传到一个名为 error.log 的文件中。npm init -y npm install express 应该在什么时候记录日志? 现在我们已经了解了日志记录的底层技术,接下来让我们谈谈应该在什么情况下记录日志内容。通常应该是以下情况之一: 在开发过程中快速调试意外行为 基于浏览器的分析或诊断日志记录 记录你服务器上传入的请求,以及所有可能发生的故障 使用库的日志调试选项来帮助用户解决问题 在 CLI 输出进度、确认消息或错误信息 我们将跳过前两种情况,并重点介绍基于 Node.js 的后三点。 服务器程序日志 可能你在服务器上记录日志的原因有多种。例如记录传入的请求并允许你从中提取诸如统计信息之类的内容,比如有多少用户在点击时发生了 404 错误,或者用户浏览器的 User-Agent。你也想知道在什么时候因为什么出错了。 如果你想编码尝试下面的内容,请先创建一个新的项目目录。在目录中创建一个 index.js 并运行以下命令来初始化项目并安装 express: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进行输出。将以下内容复制到 index.js 文件中:npm install pino express-pino-logger在这里用 console.log('%O', req) 来记录整个对象的信息。 console.log 在底层使用了 util.format 来支持 %O 占位符。你可以在 Node.js 文档中查阅它们的细节。 当你运行 node index.jsconst 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); });를 터미널에서 node index.js로 실행하면, 두 가지의 출력을 직접 확인하세요. 🎜🎜🎜🎜🎜동일해 보이지만 실제로는 시스템에서 다르게 처리됩니다. Node.js 문서를 확인해 보면 console 섹션에서 console.log가 stdout로 출력되고 console.error가 console.error를 사용하는 것을 볼 수 있습니다. 코드 >stderr. 🎜🎜각 프로세스에는 세 가지 기본 스트림을 사용할 수 있습니다. 이는 stdin, stdout 및 stderr입니다. stdin 스트림은 프로세스에 대한 입력을 처리하는 데 사용됩니다. 버튼을 누르거나 출력을 리디렉션하는 등. stdout 스트림은 프로그램 출력에 사용됩니다. 마지막으로 stderr는 오류 메시지에 사용됩니다. stderr가 왜 존재하는지, 언제 사용해야 하는지 알고 싶다면 이 글을 확인해보세요. 🎜🎜간단히 말하면, 이를 통해 셸에서 리디렉션(>)과 파이프(|)를 사용하여 프로그램과 관련된 오류 및 진단 정보를 처리할 수 있습니다. 실제 출력 결과는 별개입니다. >를 사용하면 명령 출력을 파일로 리디렉션할 수 있고, 2>를 사용하면 stderr의 출력을 파일로 리디렉션할 수 있습니다. . 예를 들어, 다음 명령은 "Hello there"를 hello.log라는 파일에 전달하고 "Bye bye"를 파일의 error.log라는 파일에 전달합니다. 🎜npm install --save-dev pino-pretty LOG_LEVEL=debug node index.js | ./node_modules/.bin/pino-pretty🎜🎜로그는 언제 기록해야 하나요? 🎜이제 로깅의 기본 기술을 이해했으므로 로그 내용이 기록되어야 하는 상황에 대해 이야기해 보겠습니다. 일반적으로 다음 중 하나여야 합니다. 🎜 개발 중 예기치 않은 동작을 빠르게 디버깅 브라우저 기반 분석 또는 진단 로깅 서버 업로드 수신 요청 기록, 및 발생할 수 있는 모든 오류 라이브러리의 로그 디버깅 옵션을 사용하여 사용자가 문제를 해결하는 데 도움을 줍니다. CLI에서 진행 상황, 확인 메시지 또는 오류 메시지를 출력합니다.🎜처음 두 가지 경우는 건너뛰고 Node.js를 기반으로 마지막 세 가지 사항에 집중하겠습니다. 🎜서버 프로그램 로그🎜서버에 로그인하는 데에는 여러 가지 이유가 있습니다. 예를 들어 들어오는 요청을 기록하고 클릭 시 404 오류가 발생한 사용자 수 또는 사용자 브라우저의 User-Agent와 같은 통계와 같은 정보를 추출할 수 있습니다. 또한 언제, 왜 문제가 발생했는지 알고 싶습니다. 🎜🎜아래 내용을 코딩하고 사용해 보고 싶다면 먼저 새 프로젝트 디렉토리를 생성해주세요. 디렉토리에 index.js를 생성하고 다음 명령을 실행하여 프로젝트를 초기화하고 express를 설치합니다. 🎜DEBUG=express:* node index.js🎜 각 요청에 대해 미들웨어로 서버를 설정하겠습니다. console.log 출력용. 다음 내용을 index.js 파일에 복사하세요. 🎜npm install debug🎜전체 개체의 정보를 기록하려면 여기에서 console.log('%O', req)를 사용하세요. console.log는 %O 자리 표시자를 지원하기 위해 내부적으로 util.format을 사용합니다. Node.js 문서에서 자세한 내용을 읽을 수 있습니다. 🎜🎜node index.js를 실행하여 서버를 시작하고 http://localhost:3000으로 이동하면 실제로 필요하지만 그렇지 않은 많은 정보가 인쇄된다는 것을 알게 될 것입니다. 모르겠어요. 🎜 如果将其更改为 console.log('%s', req) 不打印整个对象,我们就不会获得更多信息。 ![终端中输出的 "[object Object]" 信息](https://s3.amazonaws.com/com.... 可以通过编写自己的日志函数只输出我们关心的东西,但是先等等,谈谈我们通常关心的东西。虽然这些信息经常成为我们关注的焦点,但实际上可能还需要其他信息: 时间戳 - 知道事情何时发生 计算机/服务器名称 - 如果你运行的是分布式系统 进程ID - 如果你用了 pm2 来运行多个Node进程 消息 - 包含某些内容的实际消息 可能会需要的其它变量或信息 既然一切都会被转到 stdout 和 stderr,那么我们可能会想要不同的日志级别,还有配置和过滤日志的能力。 我们可以通过依赖 process 的各个部分并编写一堆 JavaScript 来获得所有这些,但关于 Node.js 的好消息是有 npm 这个生态系统,里面已经有了各种各样的库供我们使用。其中一些是: pino winston roarr bunyan(请注意,这个已经 2 年没有更新了) 我更喜欢pino,因为它速度很快。接下来看看怎样使用 pino 来帮助我们记录日志。同时我们可以用 express-pino-logger 包来记录请求。 安装 pino 和 express-pino-logger:npm install pino express-pino-logger用下面的代码更新你的 index.js文件以使用 logger 和中间件: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); });在这段代码中,我们创建了一个 pino 的实例 logger,并将其传给 express-pino-logger 创建一个新的 logger中间件来调用 app.use。另外,我们用 logger.info 替换了服务器启动时的 console.log,并在路由中添加了一个额外的 logger.debug 来显示不同的日志级别。 再次运行 node index.js 重新启动服务器,你会看到一个完全不同的输出,它每一行打印一个 JSON。再次导航到 http://localhost:3000 ,你会看到添加了另一行JSON。 如果你检查这些 JSON,将看到它包含所有前面所提到的信息,例如时间戳等。你可能还会注意到 logger.debug 语句没有打印出来。那是因为我们必须修改默认日志级别才能看到。当我们创建 logger 实例时,将值设置为 process.env.LOG_LEVEL,这意味着我们可以通过它修改值,或接受默认的 info。通过执行 LOG_LEVEL = debug node index.js,就可以调整日志级别。 在这之前要先解决一个问题,即现在的输出不适合人类阅读。pino 遵循一种理念,为了提高性能,你应该通过管道(使用 |)将输出的任何处理移动到一个单独的进程中。这包括使其可读或将其上传到云主机。这些被称为 transports。可以通过查看 transports 文档了解为什么 pino 中的错误不会写入 stderr。 让我们用工具 pino-pretty 来查看更易阅读的日志版本。在你的终端中运行:npm install --save-dev pino-pretty LOG_LEVEL=debug node index.js | ./node_modules/.bin/pino-pretty现在所有的日志都被用 | 运算符输入给 pino-pretty 命令,你的输出应该会经过美化,并且还会包含一些关键信息,而且应该是彩色的。如果再次请求 http://localhost:3000 ,你还应该看到debug消息。 有各种各样的 transports 来美化或转换你的日志。你甚至可以用 pino-colada 显示 emoji。这些对你的本地开发很有用。在生产中运行服务器之后,你可能希望将日志传输到另一个 transports,再用 > 或者用像 tee) 这样的命令将它们写入磁盘以便稍后处理。 这个文档 中还将包含有关轮换日志文件、过滤和把日志写入不同文件等内容的信息。 库的日志 现在讨论一下怎样有效地为我们的服务器程序编写日志,为什么不对我们的库使用相同的技术呢? 问题是你的库可能希望通过记录日志来进行调试,但是不应该与使用者的程序相混淆。如果需要调试某些内容,使用者应该能够启用日志。默认情况下,你的库应该是静默的,并将是否输出日志的决策权留给用户。 一个很好的例子是 express。 express 的底层有很多东西,你可能想在调试自己的程序时偷看它。如果我们查阅 express 文档,就会注意到你可以在自己的命令之前添加 DEBUG=express:*,如下所示:DEBUG=express:* node index.js如果你运行这个命令,将看到许多其他的输出,这些可帮助你调试程序中的问题。 如果你没有启用调试日志记录,则不会看到任何此类日志。这是通过一个称为 debug 的包来完成的。它允许我们在“命名空间”下编写日志消息,如果库的用户包含该命名空间或在 DEBUG 环境变量 中匹配了它的通配符,就会输出这些。要使用 debug 库,首先要安装它:npm install debug让我们通过创建一个名为 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 };这将创建一个带有命名空间 mylib:randomid 的新 debug 记录器,然后将两条消息输出到日志。让我们在前面的 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。最简单的方法是在启动 javascript 脚本的命令之前使用 Node.js 的 -r 或 --require 标志来 require 模块。使用如下命令重新运行你的服务器(假设你安装了pino-colada):DEBUG=mylib:randomid node -r pino-debug index.js | ./node_modules/.bin/pino-colada你现在将用与程序日志相同的格式查看库的调试日志。 CLI 输出 本文介绍的最后一个案例是针对 CLI 进行日志记录的特殊情况。我的理念是将“逻辑日志”与 CLI 的输出 “日志” 分离。对于所有的逻辑日志,你应该用像 debug 这样的库。这样你或其他人就可以重新使用该逻辑,而不受 CLI 的特定用例的约束。 当你用 Node.js 构建 CLI 时,可能希望添加一些看上去很漂亮颜色,或者用有视觉吸引力的方式格式化信息。但是,在构建 CLI 时,应该记住以下这几种情况。 一种情况是你的 CLI 可能会在持续集成(CI)系统的上下文中使用,因此你可能希望删除颜色和花哨的装饰输出。一些 CI 系统设置了一个名为 CI 的环境标志。如果你想更安全地检查自己是否在 CI 中,那就是使用像 is-ci 这样的包去支持一堆 CI 系统。 像 chalk 这样的库已经为你检测了CI 并为你删除了颜色。我们来看看它的样子。 使用 npm install chalk 安装 chalk 并创建一个名为 cli.js 的文件。将以下内容复制到其中:const chalk = require('chalk'); console.log('%s Hi there', chalk.cyan('INFO'));Now if you would run this script using node cli.js you'll see colored output.现在如果你用 node cli.js 运行这个脚本,将会看到彩色输出。 但是如果你用 CI=true node cli.js 运行它,你会看到颜色被消除了: 你要记住的另一个场景是 stdout 是否以终端模式运行,也就是将内容写入终端。如果是这种情况,我们可以使用 boxen 之类的东西显示所有漂亮的输出。如果不是,则可能会将输出重定向到文件或用管道传输到某处。 你可以通过检查相应流上的 isTTY 属性来检查 stdin、stdout 或 stderr 是否处于终端模式。例如:process.stdout.isTTY。 TTY 的意思是 “电传打印机(teletypewriter)”,在这种情况下专门用于终端。 根据 Node.js 进程的启动方式,这三个流每个流的值可能不同。你可以在 Node.js 文档的"process I/O" 这一部分中详细了解它。 让我们来看看 process.stdout.isTTY 的值在不同情况下是如何变化的。先更新你的 cli.js :const chalk = require('chalk'); console.log(process.stdout.isTTY); console.log('%s Hi there', chalk.cyan('INFO'));在终端中运行 node cli.js,你会看到输出的 true 被着色了。 之后运行相同的内容,但是将输出重定向到一个文件,然后检查内容:node cli.js > output.log cat output.log你会看到这次它打印了 undefined 后面跟着一个简单的无色消息,因为 stdout 的重定向关闭了它的终端模式。因为 chalk 用了 supports-color,它们会在相应的流上检查 isTTY。 像 chalk这样的工具已经为你处理了这种行为,但是在开发 CLI 时,你应该始终了解 CLI 可能在 CI 模式下运行或重定向输出的情况。它还可以帮助你进一步获得 CLI 的体验。例如你可以在终端中以漂亮的方式排列数据,如果isTTY 是 undefined ,你可以切换到更容易解析的方式。 总结 刚开始用 JavaScript 开发时用 console.log 记录你的第一行日志确实很快,但是当你将代码投入生产环境时,应该考虑更多关于日志记录的内容。本文纯粹是对各种方式和可用的日志记录解决方案的介绍。我建议你去看一些自己喜欢的开源项目,看看它们是怎样解决日志记录问题的,还有它们所用到的工具。 如果你知道或找到了我没有提及的工具,或者有什么疑问,请留言。 原文地址: https://www.twilio.com/blog/guide-node-js-logging 相关推荐:node js教程