いよいよWebサーバのログをScribeを通して処理してみます。examplesディレクトリに入っていた、scribe_catとscribe_ctrlはそのまま使えそうなのでこれを利用してみます。
# cp examples/{scribe_cat,scribe_ctrl} /usr/local/bin/
まず、ログサーバ(ログを集約するサーバ)の設定をします。このサーバに各Webサーバのログが書き込まれていきます。設定ファイルは/usr/local/etc/scribeの下に置くものとします。
# mkdir /usr/local/etc/scribe # mkdir /var/log/scribe # touch /usr/local/etc/scribe/scribed.conf
ログサーバの設定ファイル(scribed.conf)の内容は下記になります。
port=1463 # 待ち受けポート max_msg_per_second=2000000 # 一秒間に受け取るメッセージ数 check_interval=3 # チェックする間隔(Store) # Web server <store> category=www* # wwwではじまるカテゴリを処理 type=buffer # buffer storeを利用 target_write_size=20480 # バッファサイズ(これ以上溜まると書き出す) max_write_interval=1 # 書き出す間隔(バッファサイズに依存せずに一定期間で処理する間隔) buffer_send_rate=2 # 処理する間隔 retry_interval=30 # primaryに失敗してからのリトライ間隔 retry_interval_range=10 # リトライ間隔の幅(この幅でランダムに試行する) <primary> type=file # file storeを利用 fs_type=std # stdのみサポート file_path=/home/www/logs # ログを書き出す場所 base_filename=access_log # ログファイル名 max_size=100000000 # ローテート最大サイズ rotate_period=daily # ローテート間隔(daily=日ごと) rotate_hour=0 # 何時にローテートするか(0時) rotate_minute=5 # 何分にローテートするか(5分) add_newlines=1 # 改行するか(1=する) create_symlink=true # 最新ファイルへのシンボリックリンクを設定 </primary> # primaryの書き込みに失敗した場合の予備 <secondary> type=file fs_type=std file_path=/tmp base_filename=access_log max_size=3000000 </secondary> </store> # 処理されなかったメッセージの保存先 <store> category=default # defaultにすると処理されなかったものがくる type=buffer target_write_size=20480 max_write_interval=1 buffer_send_rate=2 retry_interval=30 retry_interval_range=10 <primary> type=file fs_type=std file_path=/var/log/scribe base_filename=scribed.log max_size=1000000 </primary> <secondary> type=file fs_type=std file_path=/tmp base_filename=scribed.log max_size=3000000 </secondary> </store>
scribedの起動スクリプトは下記のようなものを作りました。
#!/bin/sh # # Scribed Startup script for the scribe daemon # # chkconfig: - 83 13 # description: Scribed. # # processname: scribed # config: /usr/local/etc/scribe/scribed.conf # pidfile: /var/run/scribed.pid # # Source function library . /etc/rc.d/init.d/functions if [ -f /etc/sysconfig/scribed ]; then . /etc/sysconfig/scribed fi if [ -z "$SCRIBED_CONF_PATH" ]; then SCRIBED_CONF_PATH="/usr/local/etc/scribe/scribed.conf" fi prog="scribed" lockfile="/var/lock/subsys/$prog" scribed="/usr/local/bin/scribed" scribe_ctrl="/usr/local/bin/scribe_ctrl" RETVAL=0 start() { echo -n $"Starting $prog: " $scribed -c $SCRIBED_CONF_PATH > /dev/null 2>&1 & RETVAL=$? if [ $RETVAL -eq 0 ]; then success touch $lockfile fi echo return $RETVAL } stop() { echo -n $"Stopping $prog: " killproc $scribed RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $lockfile return $RETVAL } status() { $scribe_ctrl status } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; status) status ;; *) echo $"Usage: $0 {start|stop|restart|status}" RETVAL=1 esac exit $RETVAL
次にWebサーバ(ログの送信元サーバ)の設定をします。設定ファイルの保存先や起動スクリプトなどはログサーバと同じです。今回は念のためにログをネットワーク先(ログサーバ)とローカル二つに保存することにします。
port=1463 max_msg_per_second=2000000 check_interval=3 # Web server <store> category=www* type=multi # multi storeネットワークとローカルで保存 target_write_size=20480 max_write_interval=1 # ネットワーク保存 <store0> type=network # ネットワーク転送する remote_host=192.168.1.2 # 転送先ホスト remote_port=1463 # 転送先ポート </store0> # ローカル保存 <store1> type=file fs_type=std file_path=/home/www/logs base_filename=access_log max_size=100000000 rotate_period=daily rotate_hour=0 rotate_minute=5 add_newlines=0 create_symlink=true </store1> </store> <store> category=default type=buffer target_write_size=20480 max_write_interval=1 buffer_send_rate=2 retry_interval=30 retry_interval_range=10 <primary> type=file fs_type=std file_path=/var/log/scribe base_filename=scribed.log max_size=1000000 </primary> <secondary> type=file fs_type=std file_path=/tmp base_filename=scribed.log max_size=3000000 </secondary> </store>
設定は以上です。両方のサーバでscribedが正常に起動できるか確認してください。次にWebサーバとなるApacheのログ出力をファイルから、Scribeへの出力に切り替えます。とりあえず、エラーログはそのままファイルへと出力、アクセスログをScribeに出力することにします。
パイプを使いScribeに渡すことになりますが、scribe_catにそのまま渡すだけではうまく動きませんでした。どうやらパイプを渡す先のプログラムをプロセス上にあげておく必要があるようです。(おそらくログ出力の負荷を減らすため?)
scribe_httpdというシェルプログラムを作り、その中で標準出力を受けながらループすることにしました。
## /usr/local/bin/scribe_httpd ## このシェルプログラムからscribe_catへ渡す #!/bin/sh while /bin/true do read line echo $line | /usr/local/bin/scribe_cat $1 usleep 100000 done
上記のシェルプログラムを使い、パイプ経由でログを出力します。
# httpd.confまたはextra/httpd-vhosts.confなど <VirtualHost *:80> ServerName www.example.com DocumentRoot "/home/www.example.com/public_html" # ErrorLogはファイルに出力 ErrorLog "/home/www/logs/www.example.com/error_log" # CustomLogはパイプを使ってScribeに出力 CustomLog "| /usr/local/bin/scribe_httpd www.example.com" combined </VirtualHost>
ちゃんとScribe経由で出力されたのですが一つ問題が・・・。負荷がけっこう高いようです。scribe_httpdがログ出力の個数分プロセスに立ち上がるようなので、バーチャルホストの数やアクセスが増えたらたいへんそうです。CPUの負荷が高いようなので適当に作ったシェルスクリプトがやばいんでしょうか?毎回scribe_catを呼び出すというようなことをせずに、直接Scribeにログを渡すような形にしてやれば、負荷もけっこう下がりそうです。
無事に成功?ということでこれで終わりにしたいと思います。いまさらですが、ScribeでWebサーバのログを集約するのはあまり向かないような気も・・・。しばらく運用してみて問題がおきたら報告していきたいと思います。