Node.js管道控制台错误到另一个程序(使其异步)

时间:2018-01-18 16:05:49

标签: node.js asynchronous logging

来自Expressjs documentation

  

为了让您的应用完全异步,您仍然想要管道   console.err()到另一个程序

Qestions:

  1. 用stdout和stderr重定向到不阻止事件循环运行我的节点应用程序是否足够?像这样:node app 2>&1 | tee logFile
  2. 如果ad.1答案为真,那么在使用Winston或Bunyan时如何实现非阻塞日志记录?他们有一些内置机制来实现这一点,或者他们只是将数据保存到特定文件浪费当前Node.js进程的cpu时间?或者可能要实现trully异步日志记录,他们应该将数据传输到子进程,执行"保存到文件" (它仍然表现积极吗?)?如果我的思维方式错了,任何人都可以解释或纠正我吗?

  3. 已编辑的部分:我可以假设从流程A,B,......等到流程L的管道数据对于此特定流程(A,B,...)更便宜而不是写入文件(或通过网络发送)。 要点: 我正在为使用nodejs集群的应用程序设计logger。 简而言之 - 进程(L)之一将处理来自其他人的数据流,(A,B,......)。 进程L将对消息进行排队(例如逐行或其他特殊分隔符)并将其逐个记录到文件,db或其他任何位置。 这种方法的优点是减少了可能花费更多时间完成工作的流程负载。 还有一件事 - 假设是简化这个库的使用,因此用户只需要包含这个记录器而不需要通过shell进行任何额外的交互(流重定向)。 你认为这个解决方案有意义吗?也许你知道一个已经这样做的图书馆?

2 个答案:

答案 0 :(得分:1)

让我们先建立一些地面......

写入终端屏幕(console.log()等),写入文件(fs.writeFile()fs.writeFileSync()等)或将数据发送到流process.stdout.write(data)等。 )将始终"阻止事件循环"。为什么?因为这些函数的某些部分总是用JavaScript编写。这些函数所需的最少工作量是获取输入并将其交给某些本机代码,但是某些JS将始终执行。

由于JS参与其中,它将不可避免地阻止"阻止"事件循环,因为JavaScript代码总是在一个线程上执行,无论如何。

这是件坏事......?

没有。处理某些日志数据并将其发送到文件或流所需的时间非常少,并且对性能没有显着影响。

这什么时候会是坏事,那么......?

你可以做一些通常被称为"同步"的事情来伤害你的应用程序。 I / O操作 - 即写入文件,实际上没有执行任何其他JavaScript代码,直到写完成。执行此操作时,将所有数据交给底层本机代码,理论上可以继续在JS空间中执行其他工作,您有意决定等到本机代码以结果回复您。 这将"阻止"你的事件循环,因为这些I / O操作比执行常规代码要花费更长的时间(磁盘/网络往往是计算机中最慢的部分)。

现在,让我们回到写stdout / stderr

来自Node.js'文档:

  

process.stdout和process.stder与其他Node.js流的重要区别在于:

     
      
  1. 它们分别由console.log()和console.error()内部使用。
  2.   
  3. 他们无法关闭(end()会抛出)。
  4.   
  5. 他们永远不会完成'完成'事件
  6.   
  7. 写入可能是同步的,具体取决于流的连接方式以及系统是Windows还是POSIX:      
        
    • 文件:Windows和POSIX上的同步
    •   
    • TTY(终端):在Windows上异步,在POSIX上同步
    •   
    • 管道(和套接字):在Windows上同步,在POSIX上是异步的
    •   
  8.   

我假设我们正在使用下面的POSIX系统。

在实践中,这意味着当你的Node.js'输出流不是管道输入,而是直接发送到TTY,向控制台写入内容将阻止事件循环,直到将整个数据块发送到屏幕。但是,如果我们将输出流重定向到其他东西(进程,文件等),那么当我们向控制台Node.js写入内容时,它将不会等待操作完成并继续执行其他JavaScript代码它将数据写入该输出流

在实践中,我们可以在同一时间段执行更多JavaScript

有了这些信息,您现在应该能够自己回答所有问题:

  1. 如果您没有向控制台写任何内容,则无需重定向Node.js进程的stdout / stderr,或者如果不这样做,则只能重定向其中一个流写任何东西到另一个。无论如何,您可以重定向它们,但如果您不使用它们,您将无法获得任何性能优势。
  2. 如果您将记录器配置为将日志数据写入流,那么它将不会过多地阻止您的事件循环(除非涉及一些繁重的处理)。
  3.   

    如果您对此应用程序的性能非常,请不要使用Winston或Bunyan进行日志记录 - 它们非常慢。请改用pino - 请参阅自述文件中的基准。

答案 1 :(得分:0)

要回答(1)我们可以深入了解Express文档,您将看到指向Console的Node.js文档的链接,该文档链接到process I/O上的Node文档。它描述了process.stdout和process.stderr的行为:

  

process.stdout和process.stder与其他Node.js流的重要区别在于:

     
      
  1. 它们分别由console.log()和console.error()内部使用。
  2.   
  3. 他们无法关闭(end()会抛出)。
  4.   
  5. 他们永远不会发出'结束'事件。
  6.   
  7. 写入可能是同步的,具体取决于流连接的内容以及系统是Windows还是POSIX:      
        
    • 文件:Windows和POSIX上的同步
    •   
    • TTY(终端):在Windows上异步,在POSIX上同步
    •   
    • 管道(和套接字):在Windows上同步,在POSIX上是异步的
    •   
  8.   

有了这个,我们可以尝试了解node app 2>&1 | tee logFile会发生什么:

  • Stdout和stderr通过管道传输到进程tee
  • tee写入终端和文件logFile。

这里的重要部分是 stdout和stderr通过管道传输到进程,这意味着它应该是异步的。

关于(2)它将取决于你如何配置Bunyan或Winston:

  • Winston具有Transports的概念,它基本上允许您配置日志的位置。如果您想要异步日志,则应使用Console Transport以外的任何记录器。使用文件传输应该没问题,因为它应该为此创建一个文件流对象,这是异步的,并且不会阻止节点进程。

  • Bunyan有一个类似的配置选项:Streams。根据他们的文档,它可以接受任何流接口。只要你在这里避免使用process.stdout和process.stderr流就可以了。