简体   繁体   English

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

[英]Node.js pipe console error to another program (make it async)

From Expressjs documentation : 从Expressjs 文档中

To keep your app purely asynchronous, you'd still want to pipe console.err() to another program 为了保持您的应用程序完全异步,您仍然需要将console.err()传递到另一个程序

Qestions: 问题:

  1. Is it enough to run my node app with stdout and stderr redirect to not block event loop ? 用stdout和stderr redirect运行我的节点应用程序是否足以阻止事件循环就足够了? Like this: node app 2>&1 | tee logFile 像这样: node app 2>&1 | tee logFile node app 2>&1 | tee logFile ? node app 2>&1 | tee logFile吗?
  2. If ad.1 answer is true, then how to achieve non-blocking logging while using Winston or Bunyan? 如果ad.1回答为是,那么在使用Winston或Bunyan时如何实现非阻塞日志记录? They have some built in mechanism to achieve this or they just save data to specific file wasting cpu time of current Node.js process ? 他们有一些内置的机制来实现这一目标,还是只是将数据保存到特定文件中, 浪费了当前Node.js进程的CPU时间 Or maybe to achieve trully async logging they should pipe data to child process that performs "save to file" (is it still performance positive?) ? 还是为了实现真正的异步日志记录,他们应该将数据通过管道传递给执行“保存到文件”的子进程(它仍然对性能有好处吗?)? Can anyone explain or correct me if my way of thinking is just wrong? 如果我的思维方式是错误的,谁能解释或纠正我?

  3. Edited part : I can assume that piping data from processes A, B, ...etc to process L is cheaper for this specific processes (A, B, ...) than writing it to file (or sending over network). 编辑部分 :我可以假设从进程A,B,...等到进程L的管道数据对于该特定进程(A,B,...)比将其写入文件(或通过网络发送)便宜。 To the point: I am designing logger for application that uses nodejs cluster. 重点:我正在为使用nodejs集群的应用程序设计记录器。 Briefly - one of processes (L) will handle data streams from others, (A, B, ...). 简要地说-进程(L)中的一个将处理来自其他进程(A,B,...)的数据流。 Process L will queue messages (for example line by line or some other special separator) and log it one by one into file, db or anywhere else. 进程L将对消息进行排队(例如,逐行或其他特殊分隔符),并将消息一个一个地记录到文件,db或其他任何位置。 Advantage of this approach is reducing load of processes that can spent more time on doing their job. 这种方法的优点是减少了可以在工作上花费更多时间的流程的负载。 One more thing - assumption is to simplify usage of this library so user will only include this logger without any additional interaction (stream redirection) via shell. 还有一件事-假设是简化该库的使用,因此用户将仅包括该记录器,而无需通过shell进行任何其他交互(流重定向)。 Do you think this solution makes sense? 您认为此解决方案有意义吗? Maybe you know a library that already doing this? 也许您知道一个已经在这样做的图书馆?

Let's set up some ground level first... 让我们先设置一些地面...

Writing to a terminal screen ( console.log() etc.), writing to a file ( fs.writeFile() , fs.writeFileSync() etc.) or sending data to a stream process.stdout.write(data) etc.) will always "block the event loop". 写入终端屏幕( console.log()等),写入文件( fs.writeFile()fs.writeFileSync()等)或将数据发送到流process.stdout.write(data)等。 )将始终“阻止事件循环”。 Why? 为什么? Because some part of those functions is always written in JavaScript. 因为这些功能的某些部分始终是用JavaScript编写的。 The minimum amount of work needed by these functions would be to take the input and hand it over to some native code, but some JS will always be executed. 这些功能所需的最少工作量是将输入并移交给某些本机代码,但始终会执行一些JS。

And since JS is involved, it will inevitably "block" the event loop because JavaScript code is always executed on a single thread no matter what. 而且由于涉及到JS,因此无论如何,JavaScript代码总是在单个线程上执行,因此不可避免地会“阻塞”事件循环。

Is this a bad thing...? 这是坏事吗...?

No. The amount of time required to process some log data and send it over to a file or a stream is quite low and does not have significant impact on performance. 否。处理某些日志数据并将其发送到文件或流所需的时间很短,并且不会对性能产生重大影响。

When would this be a bad thing, then...? 什么时候这会是一件坏事,然后...?

You can hurt your application by doing something generally called a "synchronous" I/O operation - that is, writing to a file and actually not executing any other JavaScript code until that write has finished . 通过执行通常称为“同步” I / O操作的操作,可能会损害您的应用程序,即,写入文件,并且实际上直到写入完成才执行任何其他JavaScript代码。 When you do this, you hand all the data to the underlying native code and while theoretically being able to continue doing other work in JS space, you intentionally decide to wait until the native code responds back to you with the results. 当您执行此操作时,您会将所有数据交给底层的本机代码,并且在理论上可以继续在JS空间中执行其他工作时,您有意决定等到本机代码对结果做出回应。 And that will "block" your event loop , because these I/O operations can take much much longer than executing regular code (disks/networks tend to be the slowest part of a computer). 这将“阻塞”您的事件循环 ,因为这些I / O操作可能比执行常规代码花费更多的时间(磁盘/网络通常是计算机中最慢的部分)。

Now, let's get back to writing to stdout / stderr . 现在,让我们回到写stdout / stderr

From Node.js' docs: 从Node.js的文档中:

process.stdout and process.stderr differ from other Node.js streams in important ways: process.stdout和process.stderr在重要方面与其他Node.js流不同:

  1. They are used internally by console.log() and console.error(), respectively. 它们分别由console.log()和console.error()内部使用。
  2. They cannot be closed (end() will throw). 它们不能关闭(end()将抛出)。
  3. They will never emit the 'finish' event. 他们将永远不会发出“结束”事件。
  4. Writes may be synchronous depending on what the stream is connected to and whether the system is Windows or POSIX: 写入可能是同步的,具体取决于流连接到的对象以及系统是Windows还是POSIX:
    • Files: synchronous on Windows and POSIX 文件:在Windows和POSIX上同步
    • TTYs (Terminals): asynchronous on Windows, synchronous on POSIX TTY(终端):在Windows上异步,在POSIX上同步
    • Pipes (and sockets): synchronous on Windows, asynchronous on POSIX 管道(和套接字):在Windows上同步,在POSIX上异步

I am assuming we are working with POSIX systems below. 我假设我们正在使用下面的POSIX系统。

In practice, this means that when your Node.js' output streams are not piped and are sent directly to the TTY, writing something to the console will block the event loop until the whole chunk of data is sent to the screen. 实际上,这意味着当未通过管道传输Node.js的输出流并将其直接发送到TTY时,向控制台写入内容将阻止事件循环,直到将整个数据块发送到屏幕为止。 However, if we redirect the output streams to something else (a process, a file etc.) now when we write something to the console Node.js will not wait for the completion of the operation and continue executing other JavaScript code while it writes the data to that output stream . 但是,如果现在将输出流重定向到其他内容(进程,文件等),则当我们向控制台写入内容时,Node.js将不会等待操作完成并继续执行其他JavaScript代码, 同时写入数据到该输出流

In practice, we get to execute more JavaScript in the same time period . 实际上, 我们可以在同一时间段内执行更多JavaScript

With this information you should be able to answer all your questions yourself now: 有了这些信息,您现在应该可以自己回答所有问题:

  1. You do not need to redirect the stdout / stderr of your Node.js process if you do not write anything to the console, or you can redirect only one of the streams if you do not write anything to the other one. 如果您不向控制台写入任何内容,则无需重定向Node.js进程的stdout / stderr ,或者,如果您不向其他内容写入任何内容,则只能重定向其中一个流。 You may redirect them anyway, but if you do not use them you will not gain any performance benefit. 您仍然可以重定向它们,但是如果不使用它们,则不会获得任何性能优势。
  2. If you configure your logger to write the log data to a stream then it will not block your event loop too much (unless some heavy processing is involved). 如果将记录器配置为将日志数据写入流,则它不会过多地阻塞事件循环(除非涉及一些繁重的处理)。

If you care this much about your app's performance, do not use Winston or Bunyan for logging - they are extremely slow. 如果你关心这么多关于你的应用程序的性能,请不要使用温斯顿或班扬的日志-他们是极其缓慢。 Use pino instead - see the benchmarks in their readme. 请改用pino-请参阅自述文件中的基准。

To answer (1) we can dive into the Express documentation, you will see a link to the Node.js documentation for Console, which links to the Node documentation on the process I/O . 为了回答(1),我们可以深入研究Express文档,您将看到指向Console的Node.js文档的链接,该链接也指向流程I / O上的Node文档。 There it describes how process.stdout and process.stderr behaves: 那里描述了process.stdout和process.stderr的行为:

process.stdout and process.stderr differ from other Node.js streams in important ways: process.stdout和process.stderr在重要方面与其他Node.js流不同:

  1. They are used internally by console.log() and console.error(), respectively. 它们分别由console.log()和console.error()内部使用。
  2. They cannot be closed (end() will throw). 它们不能关闭(end()将抛出)。
  3. They will never emit the 'finish' event. 他们将永远不会发出“结束”事件。
  4. Writes may be synchronous depending on what the stream is connected to and whether the system is Windows or POSIX: 写入可能是同步的,具体取决于流连接到的对象以及系统是Windows还是POSIX:
    • Files: synchronous on Windows and POSIX 文件:在Windows和POSIX上同步
    • TTYs (Terminals): asynchronous on Windows, synchronous on POSIX TTY(终端):在Windows上异步,在POSIX上同步
    • Pipes (and sockets): synchronous on Windows, asynchronous on POSIX 管道(和套接字):在Windows上同步,在POSIX上异步

With that we can try to understand what will happen with node app 2>&1 | tee logFile 这样,我们可以尝试了解node app 2>&1 | tee logFile会发生什么node app 2>&1 | tee logFile node app 2>&1 | tee logFile : node app 2>&1 | tee logFile

  • Stdout and stderr is piped to a process tee Stdout和stderr用管道输送到过程tee
  • tee writes to both the terminal and the file logFile. tee将同时写入终端和文件logFile。

The important part here is that stdout and stderr is piped to a process , which means that it should be asynchronous. 这里的重要部分是将stdout和stderr通过管道传递给进程 ,这意味着它应该是异步的。

Regarding (2) it would depend on how you configured Bunyan or Winston: 关于(2),这取决于您配置Bunyan或Winston的方式:

  • Winston has the concept of Transports, which essentially allows you to configure where the log will go. Winston具有传输的概念,从本质上讲,它使您可以配置日志的存放位置。 If you want asynchronous logs, you should use any logger other than the Console Transport . 如果需要异步日志,则应使用控制台传输以外的任何记录器。 Using the File Transport should be ok, as it should create a file stream object for this and that is asynchronous, and won't block the Node process. 可以使用文件传输,因为它应该为此创建一个文件流对象,并且该对象是异步的,并且不会阻塞Node进程。

  • Bunyan has a similar configuration option: Streams . Bunyan有一个类似的配置选项: Streams According to their doc, it can accept any stream interface. 根据他们的文档,它可以接受任何流接口。 As long as you avoid using the process.stdout and process.stderr streams here you should be ok. 只要您在此处避免使用process.stdout和process.stderr流,就可以了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM