この記事はアピリッツの技術ブログ「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とか設定しましょう!