ホーム DoRuby [Ruby] 複数サーバの同じファイルをtail -fするプログラムを作ってみよう

[Ruby] 複数サーバの同じファイルをtail -fするプログラムを作ってみよう

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

複数サーバの同じファイルをtail -fするプログラムを作ってみよう

 この記事について

サーバでの作業にはかかせないログの監視。

tail -fは多くの方が利用されていると思います。

台数が少なければいいのですが、増えてくると一台ずつ

サーバにログインして→”tail -f <パス名>”とタイプして・・・

が面倒になってきます。

今回はこの手間を省くスクリプトを作成しようというのがテーマです。

 net/ssh/multi

今回使うrubygemsライブラリはnet-ssh-multiです。

複数のサーバにログインして同じ操作を行うことができるものです。

 プログラム作成

いきなりですが、以下のように作成しました。

#!/usr/bin/env ruby
#-*- coding: utf-8 -*-
require 'rubygems'
require "net/ssh/multi"
SSH_CONFIG = File.join(ENV['HOME'], ".ssh/config")

def main(hosts, paths)
  Net::SSH::Multi.start do |session|
    hosts.each do |host|
      connect_host(session, host)
    end
    tail_f(session, paths)
    session.loop
  end
rescue Interrupt
end

def connect_host(session, host)
  option = {}
  option[:config] = SSH_CONFIG if SSH_CONFIG && File.exists?(SSH_CONFIG)
  session.use host, option
end

def tail_f(session, paths)
  session.open_channel do |channel|
    channel.on_data do |ch, data|
      data.each_line do |line|
        puts ["[#{ch[:host]}]", line].join("\t")
      end
    end
    channel.exec "tail -f #{paths.join(" ")}"
  end
end    

if __FILE__ == $0
  raise "usage: mtailf <host ,host,...> <file file file...>" if ARGV.length < 2
  hosts = ARGV[0].split(/\s*,\s*/)
  paths = ARGV[1 .. -1]
  main(hosts, paths)
end

ポイントを説明していきます。

SSH_CONFIG = File.join(ENV['HOME'], ".ssh/config")

ssh_configの設定が使えるようにssh/configファイルの場所を指定しておきます。

def main(hosts, paths)
  Net::SSH::Multi.start do |session|
    hosts.each do |host|
      connect_host(session, host)
    end
    tail_f(session, paths)
    session.loop
  end
rescue Interrupt
end

mainメソッドです。

Net::SSH::Multiのブロック内でサーバへのコネクションをはり、

tailコマンドを実行しています。

tail -f はctrl+cを押すまで処理が続くので

session.loop

を実行しています。

def connect_host(session, host)
  option = {}
  option[:config] = SSH_CONFIG if SSH_CONFIG && File.exists?(SSH_CONFIG)
  session.use host, option
end

サーバへの接続です。

session.use で接続します。

def tail_f(session, paths)
  session.open_channel do |channel|
    channel.on_data do |ch, data|
      data.each_line do |line|
        puts ["[#{ch[:host]}]", line].join("\t")
      end
    end
    channel.exec "tail -f #{paths.join(" ")}"
  end
end

リモートホストに対してtail -fを実行している部分です。

channel.execでコマンドを実行して

ホストから応答があったら

channel.on_data

のブロックが実行されるかんじです。

JavaScriptっぽいですね。

ch変数にはホスト名も含まれているので

コンソールに出力する際には

puts [“[#{ch[:host]}]”, line].join(“\t”)

として、どのホストからの出力なのかがわかるようにしています。

 使い方

上記のプログラムを作成したら

ファイル名はmtailf とします。

そして

chmod 755 mtailf

と実行可能なようにパーミッションを設定します。

net-ssh-multiをインストールします。

gem install net-ssh-multi

ここまでが初期設定で、実際に使うときには

mtailf user@host01,user@host02 /path/to/file

のようにします。

引数は

第一引数→ホスト名をカンマ区切りで

第二引数以降→表示するファイルパス

以下は出力イメージです。

[host01]   ファイル行・・・・・・・・・・・
[host02]   ファイル行・・・・・・・・・・・
・
・
・
・

終了方法は

tail -fと同様に

ctrl+c です。

このコマンド打つのも面倒!となったら・・・・・・

aliasとか設定しましょう!

記事を共有

最近人気な記事