JavaScript での開発を開始するとき、最初に学ぶことは、console.log を使用してコンテンツをコンソールに記録する方法です。 JavaScript のデバッグ方法を検索すると、console.log を使用するように指示する何百ものブログ投稿や StackOverflow 記事が見つかります。これは非常に一般的な方法であるため、コード内で no-console などのリンター ルールを使用して、予期しないログ メッセージが残らないようにしています。しかし、本当に何かを録音したい場合はどうすればよいでしょうか? この記事では、さまざまな場面で記録されるログ情報と、Node.js における console.log と console.error の違いについて整理していきます。 js とは何か、そして混乱を引き起こすことなくライブラリからユーザー コンソールにログを出力する方法。 [ビデオ チュートリアルの推奨: nodejs ビデオ チュートリアル]console.log(`Let's go!`);最初の理論: Node.js の重要な詳細 ブラウザーとNode.js では console.log または console.error を使用しますが、Node.js を使用するときに覚えておくべき重要な点が 1 つあります。 Node.js で次のコードを index.js という名前のファイルに記述し、console.log('Hello there'); console.error('Bye bye'); を使用してターミナルで nodeindex.js を実行すると、両方の出力が直接表示されます。 これらは同じように見えますが、実際にはシステムによって異なる方法で処理されます。 Node.js ドキュメントを確認すると、 console セクションでは、console.log が stdout に出力され、console .error が stderr# を使用していることがわかります。 ##。 各プロセスには、使用可能なデフォルトの ストリームが 3 つあります。それらは、stdin、stdout、および stderr です。 stdin ストリームは、プロセスへの入力を処理するために使用されます。ボタンを押す、または出力をリダイレクトするなど。 stdout ストリームはプログラムの出力に使用されます。最後に、stderr はエラー メッセージに使用されます。 stderr が存在する理由と、それをいつ使用する必要があるかを理解したい場合は、この記事を参照してください。 つまり、これにより、シェル内でリダイレクト (>) とパイプ (|) を使用して、エラーと診断情報を処理できるようになります。プログラムの実際の出力とは別のものです。 > を使用するとコマンドの出力をファイルにリダイレクトできますが、 2> を使用すると stderr の出力をファイルにリダイレクトできます。たとえば、次のコマンドは、「Hello there」を hello.log という名前のファイルに渡し、「Bye bye」を error.log という名前のファイルに渡します。 node index.js > hello.log 2> error.log #いつログを記録する必要がありますか? ログの基礎となるテクノロジーを理解したところで、ログの内容を記録する必要がある状況について話しましょう。通常は次のいずれかになります。 開発中の予期しない動作を迅速にデバッグします ブラウザベースのプロファイリングまたは診断ログを作成します サーバーのアップロード受信リクエストをログに記録します。および発生する可能性のあるエラー #ライブラリのログ デバッグ オプションを使用して、ユーザーによる問題のトラブルシューティングを支援します。 CLI で進行状況、確認メッセージ、またはエラー メッセージを出力します。##最初の 2 つのケースをスキップし、Node.js に基づいた最後の 3 つのポイントに焦点を当てます。 サーバー プログラム ログ サーバーにログを記録する理由はさまざまです。たとえば、受信リクエストをログに記録し、クリック時に 404 エラーが発生したユーザーの数や、ユーザーのブラウザの User-Agent などの統計情報を抽出できるようにします。また、何か問題が発生した時期と理由も知りたいと考えています。 コーディングして次のことを試したい場合は、まず新しいプロジェクト ディレクトリを作成してください。ディレクトリに index.js を作成し、次のコマンドを実行してプロジェクトを初期化し、express をインストールします。 npm init -y npm install express Just に従って、ミドルウェアを使用してサーバーをセットアップしましょう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('%O', req) を使用して、全体の情報を記録します。物体 。 console.log は、内部で util.format を使用して、%O プレースホルダーをサポートします。詳細については、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教程