2

我有以下 Ruby 块:

ruby_block "Validate" do
  block do
    require "mixlib/shellout"
    begin
      cmd = Mixlib::ShellOut.new("/usr/local/bin/someScript.py", :timeout => 3600)
      cmd.live_stream = STDOUT
      cmd.run_command
      cmd.error!
    rescue Exception => e
      puts "Action failed..."
      return 168
    end
  end
  action :create
  notifies :create, "ruby_block[Validated]", :immediately
  not_if { node[:state][:validated] == true }
end

我想将脚本的结果记录到 STDOUT 和一个名为“/tmp/xml_diff_results.txt”的文件中。

我做的第一件事是改变:

cmd=Mixlib::ShellOut.new("/usr/local/bin/someScript.py", :timeout => 3600)

至:

cmd=Mixlib::ShellOut.new("/usr/local/bin/someScript.py > /tmp/xml_diff_results.txt", :timeout => 3600)

但是,这并没有达到我的预期。

然后我注意到了cmd.live_stream变量。有没有办法我可以利用它并做这样的事情?:

cmd.live_stream = (STDOUT > /tmp/xml_diff_results.txt)

解决方案:

我的问题的解决方案很简单,并受到@tensibai 的启发。

log_file = File.open('/tmp/chef-run.log', File::WRONLY | File::APPEND)
LOG = Logger.new(log_file)

def shell(command)
  LOG.info "Execute: #{command}"
  cmd = Mixlib::ShellOut.new(command, :timeout => 1800)
  cmd.run_command
  LOG.info "Returned: #{cmd.stdout}"
  cmd.error!
  cmd
end
4

2 回答 2

5

这不是 Ruby 甚至 Chef 的问题。这更像是一个 Bash 问题

运行命令并将其输出重定向到标准输出和文件的一种方法可能是使用tee

echo 'Hello World!' | tee output.log

所以,在你的例子中,它可能是这样的

cmd=Mixlib::ShellOut.new("/usr/local/bin/someScript.py | tee /tmp/xml_diff_results.txt", :timeout => 3600)
于 2016-11-01T00:44:50.470 回答
2

Ruby 中的另一个选项(只是内部部分)以防万一tee(Windows):

  cmd = Mixlib::ShellOut.new("/usr/local/bin/someScript.py", :timeout => 3600)
  cmd.live_stream = STDOUT
  cmd.run_command
  # new part
  log=::Tempfile.new(["xml_diff_results",".txt"])
  errlog=::File.open(log.path.gsub(".txt",".err")
  log.write(cmd.stdout)
  errlog.write(cmd.stderr)
  log.close
  errlog.close
  Chef::Log.info("Log results are in #{log.path}")
  # end of new part 
  cmd.error!

如果您在没有运行 chef-client 的情况下并且真的希望在厨师日志中打印路径,请将Chef::Log级别更改为。warn-l info

主要优点是它独立于平台,缺点是只有在命令结束执行后才会写入日志文件。

于 2016-11-02T09:35:46.830 回答