在异步钩子回调中打印日志


因为打印到控制台是异步的操作,console.log() 会导致 AsyncHooks 回调被调用。 在 AsyncHooks 回调函数中使用 console.log() 或类似的异步操作将因此导致无限递归。 当调试时,一个简单的解决方案是使用同步的日志记录操作,例如 fs.writeFileSync(file, msg, flag)。 这将打印到文件并且不会递归调用 AsyncHooks,因为它是同步的。

import { writeFileSync } from 'fs';
import { format } from 'util';

function debug(...args) {
  // 当在 AsyncHooks 回调中调试时使用这样的函数
  writeFileSync('log.out', `${format(...args)}\n`, { flag: 'a' });
}const fs = require('fs');
const util = require('util');

function debug(...args) {
  // 当在 AsyncHooks 回调中调试时使用这样的函数
  fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' });
}

如果日志记录需要异步的操作,则可以使用 AsyncHooks 本身提供的信息来跟踪导致异步操作的原因。 当日志本身导致 AsyncHooks 回调调用时,应该跳过日志。 通过这样做,否则无限递归被打破。

Because printing to the console is an asynchronous operation, console.log() will cause the AsyncHooks callbacks to be called. Using console.log() or similar asynchronous operations inside an AsyncHooks callback function will thus cause an infinite recursion. An easy solution to this when debugging is to use a synchronous logging operation such as fs.writeFileSync(file, msg, flag). This will print to the file and will not invoke AsyncHooks recursively because it is synchronous.

import { writeFileSync } from 'fs';
import { format } from 'util';

function debug(...args) {
  // Use a function like this one when debugging inside an AsyncHooks callback
  writeFileSync('log.out', `${format(...args)}\n`, { flag: 'a' });
}const fs = require('fs');
const util = require('util');

function debug(...args) {
  // Use a function like this one when debugging inside an AsyncHooks callback
  fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' });
}

If an asynchronous operation is needed for logging, it is possible to keep track of what caused the asynchronous operation using the information provided by AsyncHooks itself. The logging should then be skipped when it was the logging itself that caused AsyncHooks callback to call. By doing this the otherwise infinite recursion is broken.