URAMIRAIKAN

1020のなれの果て (since 2005.6.19)

Apacheでserver-statusの情報を収集する

 Apacheでmod_statusから情報を自動収集してCSVにまとめてほしいという要望をもらったときに作ったスクリプトです。

 かなり昔に作ったスクリプトですが、最近また使うことになりそうなので記憶の掘り起こしと備忘録に。

 Apacheは構築済みとして、"mod_status"関連のステータスは下記の通りローカルからのアクセスのみを許可(この辺は環境によって適当に変える)。

LoadModule status_module modules/mod_status.so ExtendedStatus On <VirtualHost *:80> ServerName localhost DocumentRoot "/var/www/html-dummy" <Location /server-status> SetHandler server-status Order deny,allow Deny from all Allow from localhost </Location> </VirtualHost>

 この状態で"http://localhost/server-status?auto"にアクセスすると、下記のようにApacheのステータスがテキストで返ってきます。

[root@www tmp]# curl http://localhost/server-status?auto
Total Accesses: 172
Total kBytes: 1182
CPULoad: 2.34827
Uptime: 1183
ReqPerSec: .145393
BytesPerSec: 1023.13
BytesPerReq: 7037.02
BusyWorkers: 2
IdleWorkers: 9
Scoreboard: __R_W______.....................................
............................................................
............................................................
............................................................
............................

 ここまで確認できればWEBサーバ側の準備は完了です。

 あとは、この情報を収集してCSVに整形して保存するスクリプトを準備します。
 スクリプトは以下の通り。

#!/usr/bin/perl use strict; use warnings; use Socket; use FileHandle; use POSIX 'strftime'; # 出力先ディレクトリ/ファイル my $output_dir = "/tmp/out"; my $output_log = "$output_dir/apache_status.csv"; my $output_org = "$output_dir/org_log"; chk_dir($output_dir, $output_org); # アクセス情報 my $host = "localhost"; my $port = 80; my $path = "/server-status?auto"; my $http = "1.1"; my ($interval, $freq); if($ARGV[1]){ ($interval, $freq) = @ARGV; }else{ $interval = 10; $freq = 1; } my ($ip, $sockaddr, $buf, $csv, $txt); my ($line, $sc_key, $olog, $now, $date, $time); my (@params, @txtlist); my $count = 0; if(! -f $output_log){ open($csv, "> $output_log") or die "Cannot open \"$output_log\"!! : $!\n"; print $csv mk_head(), "\n"; close $csv; } while($count < $freq){ # ソケットの生成 $ip = inet_aton($host) or die "Host[$host] not found!!\n"; $sockaddr = pack_sockaddr_in($port, $ip); socket(SOCKET, PF_INET, SOCK_STREAM, 0) or die "Socket error!!\n"; # ソケットの接続 connect(SOCKET, $sockaddr) or die "Connect \"$host:$port\" error.\n"; autoflush SOCKET (1); # HTTP要求を送信 $now = strftime "%Y%m%d%H%M%S", localtime; ($params[0], $params[1]) = tr_dtm($now); $olog = "$output_org/$now.txt"; if($http eq '1.1'){ print SOCKET "GET $path HTTP/1.1\n"; print SOCKET "Host: $host\n"; print SOCKET "Connection: close\n\n"; }else{ print SOCKET "GET $path HTTP/1.0\n\n"; } # HTTP応答を受信 open($txt, "> $olog"); while(<SOCKET>){ print $txt $_; if(/Total Accesses:/){ $params[2] = tr_dec(unpack("x16A*", $_)); }elsif(/Total kBytes:/){ $params[3] = tr_dec(unpack("x14A*", $_)); }elsif(/CPULoad:/){ $params[4] = tr_dec(unpack("x9A*", $_)); }elsif(/Uptime:/){ $params[5] = tr_dec(unpack("x8A*", $_)); }elsif(/ReqPerSec:/){ $params[6] = tr_dec(unpack("x11A*", $_)); }elsif(/BytesPerSec:/){ $params[7] = tr_dec(unpack("x13A*", $_)); }elsif(/BytesPerReq:/){ $params[8] = tr_dec(unpack("x13A*", $_)); }elsif(/BusyWorkers:/){ $params[9] = tr_dec(unpack("x13A*", $_)); }elsif(/IdleWorkers:/){ $params[10] = tr_dec(unpack("x13A*", $_)); }elsif(/Scoreboard:/){ $sc_key = unpack("x12A*", $_); ( $params[11], $params[12], $params[13], $params[14], $params[15], $params[16], $params[17], $params[18], $params[19], $params[20], $params[21], ) = tr_score($sc_key); } } close $txt; chomp(@params); $line = join(",", @params); open($csv, ">> $output_log") or die "Cannot open \"$output_log\"!! : $!\n"; print $csv $line, "\n"; # 切断処理 close SOCKET; close $csv; sleep($interval); $count++; } # 終了処理 exit(0); sub tr_score{ my $score = $_[0]; my (@schar, @scount); my $key; @scount = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); @schar = split(/\B/, $score); while($key = shift(@schar)){ if($key =~ /_/){ $scount[0]++; }elsif($key =~ /S/){ $scount[1]++; }elsif($key =~ /R/){ $scount[2]++; }elsif($key =~ /W/){ $scount[3]++; }elsif($key =~ /K/){ $scount[4]++; }elsif($key =~ /D/){ $scount[5]++; }elsif($key =~ /C/){ $scount[6]++; }elsif($key =~ /L/){ $scount[7]++; }elsif($key =~ /G/){ $scount[8]++; }elsif($key =~ /I/){ $scount[9]++; }elsif($key =~ /\./){ $scount[10]++; } } return(@scount); } sub tr_dec{ my $tmpline = $_[0]; if($tmpline =~ /^\./){ $tmpline = "0$tmpline"; } return($tmpline); } sub mk_head{ my @tmplist = ( "Date", "Time", "Total Accesses", "Total kBytes", "CPULoad", "Uptime", "ReqPerSec", "BytesPerSec", "BytesPerReq", "BusyWorkers", "IdleWorkers", "Score[Waiting for Connection]", "Score[Starting up]", "Score[Reading Request]", "Score[Sending Reply]", "Score[Keepalive(read)]", "Score[DNS Lookup]", "Score[Closing connection]", "Score[Logging]", "Score[Gracefully finishing]", "Score[Idle cleanup of worker]", "Score[Open slot with no current process]", ); my $tmpline = join(",", @tmplist); return($tmpline); } sub chk_dir{ my @dirlist = @_; foreach $_(@dirlist){ if(! -d $_){ mkdir($_, 0664) or die "Cannnot create \"$_\" directory!! : $!\n"; } } return(1); } sub tr_dtm{ my $tmpline = $_[0]; my @tmpdtm = ($tmpline =~ m/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/); return("$tmpdtm[0]/$tmpdtm[1]/$tmpdtm[2]", "$tmpdtm[3]:$tmpdtm[4]:$tmpdtm[5]"); }

 定期的に情報収集するにはスクリプトをCron等で自動実行するようにします。

 "mod_status"が有効活用されているケースはあまり見たことがなかったりしますが、Apacheの標準機能なので調査やテストの第一歩として気軽に使えるのではないかと思います。
 スクリプト自体は"mod_status"の出力が変わらなければ使えるはず(Apache 2.2では確認済み)。

 スクリプト見返してたら懐かしい気分になりましたw


    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

プロフィール

1020@管理人

都内を彷徨っているインフラエンジニアとかいう雑用係。いつだって眠い…。

最近のつぶやき

@umkn1020 (07/06-17:56)
RT @sksat_tty: これは暴言ですが,Macで開発便利っつってるやつがGitリポジトリに.DS_Store入れてたら市中引き回しにして十字架に張り付けて火つける
@umkn1020 (07/03-18:57)
RT @kamo_hiroyasu: 「人口の1割は複文が処理できないのだから、そのつもりで行動しろ」と助言することが時々あるのですが、「何もしなければ、42万人死亡する」を「42万人死亡する」と誤読して「外した」と煽る人がわらわらと湧いてきたことで、説得力が増しました。
@umkn1020 (07/03-18:49)
RT @taijijiji: 外資企業が日本市場でhiring難しいとは聞いていましたがこれほどとは。。日本人の転職の心理的ハードルの高さ、英語ポジションへの苦手意識が伺える。。英語は実質的な語学スキルよりも「やっていける自信がない」「怖い」「どうせ落とされる」というメンタリテ…
@umkn1020 (07/03-13:03)
RT @yuutosi_hiyuu: 声だして笑った https://t.co/EjqAUuT3z0
@umkn1020 (07/02-16:02)
Smart LifeでIFTTT使えなくなっていたのか…

エントリーリスト

カテゴリーリスト

タグ