nach dem login kopieren< div>< div>
理论先行:node.js 的重要细节< h2>
虽然你可以在浏览器和 node.js 中使用 或 console.error< code>,但在使用 时要记住一件重要的事。当你在 中将以下代码写入名为 index.js< 的文件中时:< >console.log('hello there'); console.error('bye bye');< div>并用 node index.js< 在终端中执行它,你会直接看到两者的输出:< p>虽然它们看起来可能一样,但实际上系统对它们的处理方式是不同的。如果你查阅 文档的 console< code>部分,会看到 是输出到 stdout< 而 console .error< 用的是 stderr< code>。< p>每个进程都有三个可用的默认 stream< code>。那些是 stdin< code>,stdout< 和 code>。 流用来在处理进程的输入。例如按下按钮或重定向输出。 流用于程序的输出。最后 用于错误消息。如果你想了解为什么会有 存在,以及应该在什么时候使用它,可以查看这篇文章。< p>简而言之,这允许我们在 shell 中使用重定向(>< code>)和管道(|< code>)来处理错误和诊断信息,它们是与程序的实际输出结果是分开的。虽然 >< 允许我们将命令的输出重定向到文件中,但是 2>< 允许我们将 的输出重定向到文件中。例如,下面这个命令会将 “hello there” 传给一个名为 hello.log< 的文件并把 “bye bye” 传到一个名为 error.log< 的文件中。< >node index.js > hello.log 2> error.log< div>应该在什么时候记录日志?< h2>
现在我们已经了解了日志记录的底层技术,接下来让我们谈谈应该在什么情况下记录日志内容。通常应该是以下情况之一:< p>
- 在开发过程中快速调试意外行为< li>
- 基于浏览器的分析或诊断日志记录< li>
- 记录你服务器上传入的请求,以及所有可能发生的故障< li>
- 使用库的日志调试选项来帮助用户解决问题< li>
- 在 cli 输出进度、确认消息或错误信息< li>< ul>
我们将跳过前两种情况,并重点介绍基于 的后三点。< p>
服务器程序日志< h2>
可能你在服务器上记录日志的原因有多种。例如记录传入的请求并允许你从中提取诸如统计信息之类的内容,比如有多少用户在点击时发生了 404 错误,或者用户浏览器的 user-agent< code>。你也想知道在什么时候因为什么出错了。< p>如果你想编码尝试下面的内容,请先创建一个新的项目目录。在目录中创建一个 并运行以下命令来初始化项目并安装 express< code>:< >npm init -y npm install express< div>让我们设置一个带有中间件的服务器,每个请求只需用 code>进行输出。将以下内容复制到 文件中:< >const express="require('express');" const port="process.env.PORT" || 3000; 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); });< div>
在这里用 console.log('%o', req)< 来记录整个对象的信息。 在底层使用了 util.format< 来支持 %o< 占位符。你可以在 文档中查阅它们的细节。< p>当你运行 来启动你的服务器并导航到 http: localhost:3000 时,会发现它会打印出很多我们确实需要但不知道的信息。< p>
如果将其更改为 console.log('%s', 不打印整个对象,我们就不会获得更多信息。< p>![终端中输出的 "[object object]" 信息](https: s3.amazonaws.com com....< p>
可以通过编写自己的日志函数只输出我们关心的东西,但是先等等,谈谈我们通常关心的东西。虽然这些信息经常成为我们关注的焦点,但实际上可能还需要其他信息:< p>
- 时间戳 - 知道事情何时发生< li>
- 计算机 服务器名称 如果你运行的是分布式系统< li>
- 进程id 如果你用了
pm2< 来运行多个node进程< li>- 消息 包含某些内容的实际消息< li>
- 可能会需要的其它变量或信息< ul>
既然一切都会被转到 code>,那么我们可能会想要不同的日志级别,还有配置和过滤日志的能力。< p>
我们可以通过依赖 process< 的各个部分并编写一堆 来获得所有这些,但关于 的好消息是有 npm< 这个生态系统,里面已经有了各种各样的库供我们使用。其中一些是:< p>pino< < li>winston< li>roarr< li>bunyan< code>(请注意,这个已经 2 年没有更新了)< ul>我更喜欢pino< code>,因为它速度很快。接下来看看怎样使用 pino< 来帮助我们记录日志。同时我们可以用 express-pino-logger< 包来记录请求。< p>安装 pino="require('pino');" express-pino-logger< div>
用下面的代码更新你的 code>文件以使用 logger 和中间件:< expresspino="require('express-pino-logger');" level: process.env.log_level 'info' expresslogger="expressPino({" app.use(expresslogger); logger.debug('calling res.send'); logger.info('server div>
在这段代码中,我们创建了一个 的实例 logger< code>,并将其传给 创建一个新的 logger中间件来调用 app.use< code>。另外,我们用 logger.info< 替换了服务器启动时的 code>,并在路由中添加了一个额外的 logger.debug< 来显示不同的日志级别。< p>再次运行 重新启动服务器,你会看到一个完全不同的输出,它每一行打印一个 json。再次导航到 ,你会看到添加了另一行json。< p>
如果你检查这些 json,将看到它包含所有前面所提到的信息,例如时间戳等。你可能还会注意到 语句没有打印出来。那是因为我们必须修改默认日志级别才能看到。当我们创建 实例时,将值设置为 process.env.log_level< code>,这意味着我们可以通过它修改值,或接受默认的 info< code>。通过执行 log_level="debug" node code>,就可以调整日志级别。< p>在这之前要先解决一个问题,即现在的输出不适合人类阅读。pino< 遵循一种理念,为了提高性能,你应该通过管道(使用 |< code>)将输出的任何处理移动到一个单独的进程中。这包括使其可读或将其上传到云主机。这些被称为 transports< code>。可以通过查看 文档了解为什么 中的错误不会写入 p>让我们用工具 pino-pretty< 来查看更易阅读的日志版本。在你的终端中运行:< --save-dev pino-pretty log_level="debug" | . node_modules .bin pino-pretty< div>现在所有的日志都被用 运算符输入给 命令,你的输出应该会经过美化,并且还会包含一些关键信息,而且应该是彩色的。如果再次请求 ,你还应该看到debug< code>消息。< p>有各种各样的 transports 来美化或转换你的日志。你甚至可以用 pino-colada< 显示 emoji。这些对你的本地开发很有用。在生产中运行服务器之后,你可能希望将日志传输到另一个 transports,再用 或者用像 tee< code>) 这样的命令将它们写入磁盘以便稍后处理。< p>这个文档 中还将包含有关轮换日志文件、过滤和把日志写入不同文件等内容的信息。< p>
库的日志< h2>
现在讨论一下怎样有效地为我们的服务器程序编写日志,为什么不对我们的库使用相同的技术呢?< p>
问题是你的库可能希望通过记录日志来进行调试,但是不应该与使用者的程序相混淆。如果需要调试某些内容,使用者应该能够启用日志。默认情况下,你的库应该是静默的,并将是否输出日志的决策权留给用户。< p>
一个很好的例子是 的底层有很多东西,你可能想在调试自己的程序时偷看它。如果我们查阅 文档,就会注意到你可以在自己的命令之前添加 debug="mylib:randomid" >debug="mylib:randomid" div>如果你运行这个命令,将看到许多其他的输出,这些可帮助你调试程序中的问题。< p>
如果你没有启用调试日志记录,则不会看到任何此类日志。这是通过一个称为 debug< 的包来完成的。它允许我们在“命名空间”下编写日志消息,如果库的用户包含该命名空间或在 debug< 环境变量 中匹配了它的通配符,就会输出这些。要使用 库,首先要安装它:< debug< div>让我们通过创建一个名为 random-id.js< 的新文件来模拟我们的库,并将以下代码复制到其中:< debug="require('debug');" log="debug('mylib:randomid');" log('library loaded'); function getrandomid() log('computing random id'); outcome="Math.random()" .tostring(36) .substr(2); log('random id is "%s"', outcome); return outcome; } module.exports="{" getrandomid };< div>这将创建一个带有命名空间 mylib:randomid< 的新 记录器,然后将两条消息输出到日志。让我们在前面的 中使用它:< randomid="require('./random-id');" id="randomId.getRandomId();" res.send(`hello world [${id}]`); div>如果用 重新运行我们的服务器,它会打印前面“库”的调试日志。< p>
如果你的库的用户想要将这个调试信息放到他们的 日志中,他们可以用 团队开发的名为 pino-debug< 的库来正确的格式化这些日志。< p>用以下命令安装库:< pino-debug< div>
在我们第一次使用debug< code>之前,需要初始化pino-debug< code>。最简单的方法是在启动 javascript 脚本的命令之前使用 的 -r< --require< 标志来 require 模块。使用如下命令重新运行你的服务器(假设你安装了pino-colada< code>):< -r pino-debug pino-colada< div>你现在将用与程序日志相同的格式查看库的调试日志。< p>
cli 输出< h2>
本文介绍的最后一个案例是针对 进行日志记录的特殊情况。我的理念是将“逻辑日志”与 的输出 “日志” 分离。对于所有的逻辑日志,你应该用像 这样的库。这样你或其他人就可以重新使用该逻辑,而不受 的特定用例的约束。< p>
当你用 构建 时,可能希望添加一些看上去很漂亮颜色,或者用有视觉吸引力的方式格式化信息。但是,在构建 时,应该记住以下这几种情况。< p>
一种情况是你的 可能会在持续集成(ci)系统的上下文中使用,因此你可能希望删除颜色和花哨的装饰输出。一些 ci 系统设置了一个名为 ci< 的环境标志。如果你想更安全地检查自己是否在 中,那就是使用像 is-ci< 这样的包去支持一堆 系统。< p>像 chalk< 这样的库已经为你检测了ci 并为你删除了颜色。我们来看看它的样子。< p>使用 npm chalk< 安装 并创建一个名为 cli.js< 的文件。将以下内容复制到其中:< chalk="require('chalk');" console.log('%s hi there', chalk.cyan('info'));< div>now if you would run this script using cli.js< you'll see colored output.
现在如果你用 运行这个脚本,将会看到彩色输出。< p>
但是如果你用 ci="true" 运行它,你会看到颜色被消除了:< p>你要记住的另一个场景是 是否以终端模式运行,也就是将内容写入终端。如果是这种情况,我们可以使用 boxen< 之类的东西显示所有漂亮的输出。如果不是,则可能会将输出重定向到文件或用管道传输到某处。< p>你可以通过检查相应流上的 istty< 属性来检查 code>、stdout< 是否处于终端模式。例如:process.stdout.istty< tty< 的意思是 “电传打印机(teletypewriter)”,在这种情况下专门用于终端。< p>根据 进程的启动方式,这三个流每个流的值可能不同。你可以在 文档的"process i o" 这一部分中详细了解它。< p>
让我们来看看 process.stdout.istty< 的值在不同情况下是如何变化的。先更新你的 :< console.log(process.stdout.istty); div>在终端中运行 code>,你会看到输出的 true< 被着色了。< p>之后运行相同的内容,但是将输出重定向到一个文件,然后检查内容:< cli.js output.log cat output.log< div>
你会看到这次它打印了 undefined< 后面跟着一个简单的无色消息,因为 的重定向关闭了它的终端模式。因为 用了 supports-color< code>,它们会在相应的流上检查 像 code>这样的工具已经为你处理了这种行为,但是在开发 时,你应该始终了解 可能在 模式下运行或重定向输出的情况。它还可以帮助你进一步获得 的体验。例如你可以在终端中以漂亮的方式排列数据,如果istty< 是 ,你可以切换到更容易解析的方式。< 总结< h2>
刚开始用 开发时用 记录你的第一行日志确实很快,但是当你将代码投入生产环境时,应该考虑更多关于日志记录的内容。本文纯粹是对各种方式和可用的日志记录解决方案的介绍。我建议你去看一些自己喜欢的开源项目,看看它们是怎样解决日志记录问题的,还有它们所用到的工具。<
如果你知道或找到了我没有提及的工具,或者有什么疑问,请留言。<
原文地址: https: www.twilio.com blog guide-node-js-logging< p>< blockquote>
相关推荐:<>Das obige ist der detaillierte Inhalt von深入研究Node.js中的日志信息. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!