【问题标题】:Redirecting stdout to file nodejs将标准输出重定向到文件 nodejs
【发布时间】:2015-12-19 14:40:15
【问题描述】:

我已经创建了:

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');

谁能解释我做错了什么?

【问题讨论】:

  • 是的,我真的很惊讶您可以在可写对象上调用管道而不会出错,这是怎么回事?

标签: node.js logging stdout


【解决方案1】:

最初基于@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;
 }
}

【讨论】:

    【解决方案2】:

    @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() 恢复其正常功能,并且当调用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 似乎做了很多工作 此时。 这是一种好的做法吗,你会这样做还是在这种情况下你会怎么做 任何人都可以随时回复。

    【讨论】:

    • 也可以在 process.exit() 尝试 stream.pipleline() process.stdout 让它去
    【解决方案3】:

    结帐console.Console,普通console的父类。

    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

    【讨论】:

      【解决方案4】:

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

      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);
      • throw new Error('Crash');
      • 抛出“永远不要这样做”;
      • 抛出未定义;

      【讨论】:

      • 请注意,如果您正在覆盖 process.stdout.write,您将无法再写入控制台。
      • uncaughtException 部分是否不会在该日志文件中复制相同的错误消息,因为 stderr 无论如何都会重定向到该文件?
      • @user36476 否,因为只有在没有监听 uncaughtException 事件的情况下,节点才会打印该消息。
      【解决方案5】:

      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 的新 Writable 流(或者它本身返回 process.stdout。文档中没有对此的规范)。

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

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

      【讨论】:

      • 谢谢。你的回答很有帮助。目前我决定重写console.log方法,但希望找到更有建设性的解决方案。
      • 是的,我真的很惊讶您可以在可写对象上调用管道而不会出错,这是怎么回事?
      • 根据nodejsofficial docprocess.stdout是双工流
      • @Alex 没那么简单:“它是一个 net.Socket(它是一个双工流),除非 fd 1 指的是一个文件,在这种情况下它是一个可写流。”
      • "当 Node.js 检测到它正在运行时附加了一个文本终端 ("TTY"),process.stdin 将默认初始化为 tty.ReadStream 的实例,并且两者都 @默认情况下,987654325@ 和 process.stderr 将是 tty.WriteStream 的实例。” ——TTY | Node.js Documentation
      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-31
      • 1970-01-01
      相关资源
      最近更新 更多