将标准输出重定向到文件 nodejs

Redirecting stdout to file nodejs

我创建了:

var access = fs.createWriteStream('/var/log/node/api.access.log', { flags: 'w' });

然后管道:

process.stdout.pipe(access);

然后尝试:

console.log("test");

而且 /var/log/node/api.access.log 中什么也没有出现。但是这种方式有效:

process.stdout.pipe(access).write('test');

有人可以解释我做错了什么吗?

process.stdout 是可写的。 pipeReadable 的一种方法(参见 StreamAPI 文档:https://nodejs.org/api/stream.html

您可以在此处查看 process.stdout 的文档:https://nodejs.org/api/process.html#process_process_stdout

令人惊讶的是,您可以毫无错误地执行 process.stdout.pipe(...);。但我想这个电话什么都不做。除了返回绑定到 stdout 的新可写流(或者可能是 returns process.stdout 本身。文档中没有相关说明)。

如果你想将 stdout 重定向到一个文件,你有很多解决方案:

  • 只需使用您的命令行即可。 Windows 风格:node myfile.js > api.access.log.
  • 用您自己的对象替换控制台对象。你可以重写控制台方法。
  • 我不确定,但可以用你自己的流替换 process.stdout(你可以用它做任何你想做的事)

我通过以下方式解决了这个问题:

var access = fs.createWriteStream('/var/log/node/api.access.log');
process.stdout.write = process.stderr.write = access.write.bind(access);

当然你也可以把stdout和stderr分开。

我也强烈建议处理未捕获的异常:

process.on('uncaughtException', function(err) {
  console.error((err && err.stack) ? err.stack : err);
});

这将涵盖以下情况:

  • process.stdout.write
  • process.stderr.write
  • console.log
  • console.dir
  • console.error
  • someStream.pipe(process.stdout);
  • 抛出新错误('Crash');
  • 扔 'never do this';
  • 抛出未定义;

结帐 console.Console,正常 console 的父 class。

var myLogFileStream = fs.createWriteStream(pathToMyLogFile);

var myConsole = new console.Console(myLogFileStream, myLogFileStream);

然后您可以使用 myConsole.logmyConsole.errormyConsole.dir 等直接写入您的文件。

您也可以monkey patchprocess.stdout.write如下:

var fn = process.stdout.write;

function write() {
  fn.apply(process.stdout, arguments);
  myLogFileStream.write.apply(myLogFileStream, arguments);
}

process.stdout.write = write;

根据将 stdout 记录到文件的动机,还有其他选项可以覆盖 console._stdout

@user3173842 回复 我通过以下方式解决了这个问题:

var access = fs.createWriteStream('/var/log/node/api.access.log');
process.stdout.write = process.stderr.write = access.write.bind(access);

你明白 process.stdoutprocess.on('exit') 之后继续,因此 fs.WriteStreamprocess.stdout 之后关闭,根据 https://github.com/nodejs/node/issues/7606

所以现在问题仍然存在,如果开发人员希望 fs.Writestream.write() return 具有正常功能并且当 fs.Writestream.end 被调用时 writestream 关​​闭。开发人员将如何着手这样做我做到了

a_l = asyncify_listener
p_std_stream_m is a process stream manager object

p_std_stream_m.std_info.p_stdout_write = process.stdout.write   

process.stdout.write = w_stream.write.bind(w_stream)

process.once('beforeExit', a_l(   p_std_stream_m.handler,process.stdout,w_stream   )   )       

     where in the 'beforeExit' event listener I did
process.stdout.write = p_std_stream_m.std_info.p_stdout_write

w_stream.end()

它有效,你使用 once 方法,因为 process.stdout 似乎做了很多工作 此时。 这是好习惯吗,在这种情况下你会这样做吗? 任何人都可以随时回复。

最初基于@Anatol-user3173842 的回答

但在我的例子中,我需要挂钩 stdout & stderr 并写入文件。

所以对于那些除了写入文件之外还需要保持正常标准输出行为的人。使用以下内容。

对于非错误:

// stdout logging hook
const stdoutWrite0 = process.stdout.write;
process.stdout.write = (args) => { // On stdout write
  CustomLogger.writeToLogFile('log', args); // Write to local log file
  args = Array.isArray(args) ? args : [args]; // Pass only as array to prevent internal TypeError for arguments
  return stdoutWrite0.apply(process.stdout, args);
};

错误:

// stderr logging hook
const stderrWrite0 = process.stderr.write;
process.stderr.write = (args) => { // On stderr write
  CustomLogger.writeToLogFile('error', args); // Write to local error file
  args = Array.isArray(args) ? args : [args]; // Pass only as array to prevent internal TypeError for arguments
  return stderrWrite0.apply(process.stderr, args);
};

// uncaught exceptions
process.on('uncaughtException', (err) => {
  CustomLogger.writeToLogFile('error', ((err && err.stack) ? err.stack : err));
});

这是 CustomLogger 代码,其中我还按日期分隔日志文件:

export class CustomLogger {

 static LOGS_DIR = 'location-of-my-log-files';

 private static logDailyName(prefix: string): string {
   const date = new Date().toLocaleDateString().replace(/\//g, '_');
   return `${CustomLogger.LOGS_DIR}/${prefix}_${date}.log`;
 }

 private static writeToLogFile(prefix, originalMsg) {
   const timestamp   = Date.now();
   const fileName    = this.logDailyName(prefix);
   const logMsg      = prepareForLogFile(originalMsg);
   fs.appendFileSync(fileName, `${timestamp}\t${logMsg}\n\n`);
   return originalMsg;
 }
}