在rails应用程序的前端获取实时日志

kan*_*nna 6 ruby ssh ruby-on-rails net-ssh eventmachine

在rails 3.x应用程序中,我使用net :: ssh并向远程pc运行一些命令.我想将实时日志显示给用户的browser.like,如果有两个命令在net :: ssh中运行执行即echo "Hello",echo "Bye"被传递,然后"你好"应显示在其execution.Here后立即整理浏览器是我使用了SSH连接,并在轨道上运行的应用程序在Ruby中命令代码

Net::SSH.start( @servers['local'] , @machine_name, :password => @machine_pwd, :timeout => 30) do |ssh|      
  ssh.open_channel do |channel|
    channel.request_pty         
    channel.exec("echo 'ssh started'")                                   
    channel.exec("ruby -v") 
    channel.exec("rails -v") 
    channel.exec("echo 'ssh Finished'") 


    channel.on_close do |ch|
      puts "****shell terminated****"
    end

    channel.on_eof do |ch|
      puts "****remote end is done sending data****"            
    end
    channel.on_extended_data do |ch, type, data|
      puts "****got stderr****: #{data.inspect}"
    end
    channel.on_data do |channel, data|
      puts "****ondata****: #{data} \n"                    
      puts "****channel****: #{channel} \n"          
      $logs << data # this data to be sent immediately to browser in each go                                  
    end

  ssh.loop      
  end
end  
Run Code Online (Sandbox Code Playgroud)

这里on_data在每个命令执行中发送数据,我需要立即将这些数据发送到浏览器.有什么方法可以做到这一点.所以我可以在前端浏览器中实现实时日志.谢谢!

Uri*_*ssi 5

要实现“立即向浏览器发送数据”,您需要使用以下三种策略之一:

  • 短轮询
  • 流媒体
  • 长轮询

(在下面的例子中,我假设它$logs的类型是Queue

短轮询

短轮询是从服务器获取待处理信息的经典方式。这意味着客户端每 X 秒询问一次服务器“你有新信息吗?”,服务器回答“否”,在这种情况下客户端再睡 X 秒,或者服务器回答“是的,这是一些新信息...',然后客户端可以渲染,然后再休眠 X 秒。

这种策略的主要优点是所有浏览器和所有 ruby​​ 版本(简单的 AJAX 调用)都支持它。

此策略的缺点是您将在看到新数据之前延迟最多 X 秒。如果 X 太短 - 您将遭受大量网络开销(所有请求都为空响应)。

示例实现:

def get_logs
  available_logs = []
  while(line = $logs.pop(true) rescue nil) available_logs << line

  body available_logs.join($/)
end
Run Code Online (Sandbox Code Playgroud)

流媒体

流式策略是当您的客户端向服务器打开请求时,服务器开始向客户端发送响应,但是当可用信息结束时,它不会关闭连接,而是保持打开状态。然后,随着信息的到来,它继续在打开的套接字上传输信息。

在 Rails 4.0 中有一个ActionController::Live实现了这个策略。对于 Rails 3.2,您可以尝试查看此答案:https : //stackoverflow.com/a/4320399/1120015

示例实现:

def get_logs
  class LogConsumer
    def each
      while $channel.active?
        yield $logs.pop + $/
      end
    end
  end

  self.response_body = LogConsumer.new
end
Run Code Online (Sandbox Code Playgroud)

此解决方案与其他两个解决方案之间的主要区别在于客户端实现并不那么简单 - 客户端不能只是等待响应返回然后呈现它(如默认jQuery用法)。对于示例实现,很多地方都指向Ajax Patterns,目前显然不可用:-(。

我见过的另一个选择是使用门户插件*:

def get_logs
  available_logs = []
  while(line = $logs.pop(true) rescue nil) available_logs << line

  body available_logs.join($/)
end
Run Code Online (Sandbox Code Playgroud)

*我没有使用这个插件的经验,所以这应该作为一个研究方向,而不是一个工作示例......

长轮询

长轮询意味着您的 AJAX 客户端请求服务器获取下一个日志行。如果服务器有一个(或多个)要提供,它会将其返回给客户端,客户端呈现该行,然后再次请求。如果服务器没有要提供的线路,它不会返回空响​​应,而是挂起请求,并等待线路可用。一旦有新线路可用,它就会返回给客户。客户端呈现该行,然后立即再次请求服务器。

当您选择此策略时,您必须确保timeout在 Web 服务器或客户端中没有设置,也没有在中间的任何其他点(负载均衡器等)中设置。

示例实现:

def get_logs
  available_logs = []
  while(line = $logs.pop(true) rescue nil) available_logs << line

  if available_logs.empty?
    available_logs << $logs.pop
  end

  body available_logs.join($/)
end
Run Code Online (Sandbox Code Playgroud)