【问题标题】:What's the right way to exit node.js script with a log message?使用日志消息退出 node.js 脚本的正确方法是什么?
【发布时间】:2012-02-29 18:21:46
【问题描述】:

我有一个 node.js 脚本,它使用 WriteStream 对文件进行一些记录。在某些事件上,我想停止执行脚本,即警告登录并在此之后立即退出。作为异步的 node.js 不允许我们直接这样做:

#!/usr/local/bin/node

var fs = require('fs');
var stream = fs.createWriteStream('delme.log', { flags: 'a' });

stream.write('Something bad happened\n');
process.exit(1);

此脚本不会将消息附加到 delme.log,而不是对该文件执行任何操作。处理“退出”事件和刷新不起作用。到目前为止,在退出之前写入最后一条日志消息的唯一方法是将process.exit(1) 包装在setTimeout() 中:

#!/usr/local/bin/node

var fs = require('fs');
var stream = fs.createWriteStream('delme.log', { flags: 'a' });

stream.write('Something bad happened\n');
setTimeout(function(){
  process.exit(1);
}, 30);

但是,在这种形式下,它不会立即停止脚本执行,并且脚本将在关键事件发生后运行一段时间。所以我想知道是否还有其他方法可以通过日志消息退出脚本?

【问题讨论】:

    标签: node.js


    【解决方案1】:

    由于您想要阻止并且已经在使用流,您可能希望自己处理写入。

    var data = new Buffer('Something bad happened\n');
    fs.writeSync(stream.fd, data, 0, data.length, stream.pos);
    process.exit();
    

    【讨论】:

    • 谢谢!这是 setTimeout() 调用的一种变体,它不会阻止脚本执行。如果出现异常后不应执行代码,则此模式可能会成为问题。
    • 在我的特殊情况下,我使用 WriteStream 进行日志记录,因此实际调用将是 log.error('Something bad occurred') ,它使用适当的日志级别格式化消息并添加一些其他内容。所以在不改变记录器接口的情况下很难实现这个 sn-p。我将我的解决方法发布为替代解决方案。最初的问题得到了完美的回答。谢谢!
    【解决方案2】:

    改进。

    var fs = require('fs');
    var stream = fs.createWriteStream('delme.log', {flags: 'a'});
    
    // Gracefully close log
    process.on('uncaughtException', function () {
        stream.write('\n'); // Make sure drain event will fire (queue may be empty!)
        stream.on('drain', function() {
            process.exit(1);
        });
    });
    
    // Any code goes here...
    stream.write('Something bad happened\n');
    throw new Error(SOMETHING_BAD);
    

    try-catch 块有效,但很难看。不过,学分归@nab,我只是美化了它。

    【讨论】:

      【解决方案3】:

      要在退出之前将所有日志消息刷新到文件中,可能需要将脚本执行包装在 try-catch 块中。一旦发生了不好的事情,它就会被记录并抛出一个异常,该异常将被外部 try 捕获,可以安全地异步退出:

      #!/usr/local/bin/node
      
      var fs = require('fs');
      var stream = fs.createWriteStream('delme.log', { flags: 'a' });
      var SOMETHING_BAD = 'Die now';
      
      try {
        // Any code goes here...
        if (somethingIsBad) {
          stream.write('Something bad happened\n');
          throw new Error(SOMETHING_BAD);
        }
      } catch (e) {
        if (e.message === SOMETHING_BAD) {
          stream.on('drain', function () {
            process.exit(1);
          });
        } else {
           throw e;
        }
      }
      

      【讨论】:

        【解决方案4】:

        我认为这是正确的方法:

        process.on('exit', function (){
          // You need to use a synchronous, blocking function, here.
          // Not streams or even console.log, which are non-blocking.
          console.error('Something bad happened\n');
        });
        

        【讨论】:

          【解决方案5】:

          我主张在这个事件中只写信给 stderr - 例如琐碎的例子

          console.error(util.inspect(exception));
          

          然后让监督*进程处理日志持久性。根据我现在的理解,您不必担心在节点退出之前 stdout 和 stderr 不会刷新(尽管我确实在某些 0.2.x 版本中看到了有问题的相反行为)。

          (*) 对于监督过程,请从 supervisord、god、monit、forever、pswatch 等中选择...

          这也为使用 PaaS 提供商(如 Heroku 和 dotcloud 等)提供了一条干净的路径……让基础设施管理日志记录

          【讨论】:

          • 我更愿意(以某种方式)以编程方式解决它。我有许多不同类型的简短运行脚本。其中一些只是警告 STDERR,一些记录数据到文件系统。我需要的是一种统一的方法来退出带有日志消息的脚本,而不依赖于外部软件。无论如何感谢您的提示:)
          猜你喜欢
          • 1970-01-01
          • 2011-09-22
          • 2015-03-01
          • 1970-01-01
          • 2021-05-01
          • 2014-08-13
          • 2015-12-17
          • 2012-01-19
          • 2017-08-29
          相关资源
          最近更新 更多