Server Statusの情報収集スクリプト
以前にこんなエントリを書きました。
サーバー運用していると、定期的に情報収集したくなるものです。
ということで、Server Status 情報をCSVファイルにするスクリプトを作ってみました。
動くものができたので、公開してみる事にします。
Perlで書いています。モジュールを沢山使っている訳ではないので、
Perlが動く環境であれば、大体動くかと。。
利用はご自由にどうぞ。
#!/usr/bin/perl # Author : think-t # Blog : http://d.hatena.ne.jp/think-t use warnings; use strict; use LWP::UserAgent; use Fcntl; my $hostname = "127.0.0.1"; # Name of server my $port = "80"; # Port on server my $address = "server-status/?auto"; # Server Status Address my $log_directory = "/var/log"; # Log Directory my $url = "http://$hostname:$port/$address"; my ( $year, $month, $month_of_day, $hour, $minute ) = &get_current_time ( ); my $yyyyMMdd = sprintf ( "%04d%02d%02d", $year, $month, $month_of_day ); my $log_file = "$log_directory/$yyyyMMdd.server-status.log"; my %server_status = ( 'total_access' => '', 'total_kbytes' => '', 'uptime' => '', 'req_per_sec' => '', 'bytes_per_sec' => '', 'bytes_per_req' => '', 'busyworkers' => '', 'idleworkers' => '', 'scoreboard' => '', ); my %scoreboard_count = ( '_' => 0, # Waiting for Connection 'S' => 0, # Starting up 'R' => 0, # Reading Request 'W' => 0, # Sending Reply 'K' => 0, # Keepalive(read) 'D' => 0, # DNS Lookup 'C' => 0, # Closing connection 'L' => 0, # Logging 'G' => 0, # Gracefully finishing 'I' => 0, # Idle cleanup of worker '.' => 0, # Open slot with no current process ); my $response = &get_server_status ( ); if ( $response -> is_success ){ my $response_data = $response -> content; %server_status = &pick_out_server_status_value ( $response_data, \%server_status ); %scoreboard_count = &count_scoreboard_count ( $server_status{'scoreboard'}, \%scoreboard_count ); my $message = &collect_server_status_value ( \%server_status, \%scoreboard_count ); &write_log ( $log_file, $message ); } else { my $date = sprintf ( "%04d/%02d/%02d", $year, $month, $month_of_day ); my $time = sprintf ( "%02d:%02d", $hour, $minute ); my $message = "$date,$time,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"; &write_log ( $log_file, $message ); } sub get_current_time { my ( $second, $minute, $hour, $month_of_day, $month, $year ) = localtime ( ); $year += 1900; $month++; return ( $year, $month, $month_of_day, $hour, $minute ); } sub get_server_status { my $agent = LWP::UserAgent -> new; my $request = HTTP::Request -> new ( GET => $url ); my $response = $agent -> request ( $request ); return $response; } sub pick_out_server_status_value { my ( $response_data, $server_status ) = @_; if ( $response_data =~ m|^Total\ Accesses:\ (\S+)|m ) { $server_status{'total_access'} = $1 }; if ( $response_data =~ m|^Total\ kBytes:\ (\S+)|m ) { $server_status{'total_kbytes'} = $1 }; if ( $response_data =~ m|^Uptime:\ (\S+)|m ) { $server_status{'uptime'} = $1 }; if ( $response_data =~ m|^ReqPerSec:\ (\S+)|m ) { $server_status{'req_per_sec'} = $1 }; if ( $response_data =~ m|^BytesPerSec:\ (\S+)|m ) { $server_status{'bytes_per_sec'} = $1 }; if ( $response_data =~ m|^BytesPerReq:\ (\S+)|m ) { $server_status{'bytes_per_req'} = $1 }; if ( $response_data =~ m|^BusyWorkers:\ (\S+)|m ) { $server_status{'busyworkers'} = $1 }; if ( $response_data =~ m|^IdleWorkers:\ (\S+)|m ) { $server_status{'idleworkers'} = $1 }; if ( $response_data =~ m|^Scoreboard:\ (\S+)|m ) { $server_status{'scoreboard'} = $1 }; return %server_status; } sub count_scoreboard_count { my ( $scoreboard, $scoreboard_count ) = @_; $scoreboard_count{'_'} = $scoreboard =~ tr/_/_/; $scoreboard_count{'S'} = $scoreboard =~ tr/S/S/; $scoreboard_count{'R'} = $scoreboard =~ tr/R/R/; $scoreboard_count{'W'} = $scoreboard =~ tr/W/W/; $scoreboard_count{'K'} = $scoreboard =~ tr/K/K/; $scoreboard_count{'D'} = $scoreboard =~ tr/D/D/; $scoreboard_count{'C'} = $scoreboard =~ tr/C/C/; $scoreboard_count{'L'} = $scoreboard =~ tr/L/L/; $scoreboard_count{'G'} = $scoreboard =~ tr/G/G/; $scoreboard_count{'I'} = $scoreboard =~ tr/I/I/; $scoreboard_count{'.'} = $scoreboard =~ tr/././; return %scoreboard_count; } sub collect_server_status_value { my ( $server_status, $scoreboard_count ) = @_; my ( $year, $month, $month_of_day, $hour, $minute ) = &get_current_time ( ); my $date = sprintf ( "%04d/%02d/%02d", $year, $month, $month_of_day ); my $time = sprintf ( "%02d:%02d", $hour, $minute ); my $message = "$date,$time,$server_status{'total_access'},$server_status{'total_kbytes'},$server_status{'uptime'}," . "$server_status{'req_per_sec'},$server_status{'bytes_per_sec'},$server_status{'bytes_per_req'}," . "$server_status{'busyworkers'},$server_status{'idleworkers'}," . "$scoreboard_count{'_'},$scoreboard_count{'S'},$scoreboard_count{'R'},$scoreboard_count{'W'}," . "$scoreboard_count{'K'},$scoreboard_count{'D'},$scoreboard_count{'C'},$scoreboard_count{'L'}," . "$scoreboard_count{'G'},$scoreboard_count{'I'},$scoreboard_count{'.'}"; return $message; } sub write_log { my ( $log_file, $message ) = @_; my $header = "date,time,total_access,total_kbytes,uptime," . "req_per_sec,bytes_per_sec,bytes_per_req,busyservers,idleservers," . "waiting,starting_up,reading,sending,reading_keepalive," . "look_up_dns,closing,logging,finishing_gracefully,clean_up_idle,open_slot"; if ( -f $log_file ){ sysopen ( my $fh, $log_file, O_WRONLY|O_APPEND|O_CREAT ) or die $!; print $fh $message . "\n"; close ( $fh ); } else { sysopen ( my $fh, $log_file, O_WRONLY|O_APPEND|O_CREAT ) or die $!; print $fh $header . "\n"; print $fh $message . "\n"; close ( $fh ); } } exit 0;
設定など
使用する場合は、「mod_status」を有効にし、「ExtendedStatus On」として下さい。
また、必要に応じて、以下の部分を環境に合わせてカスタマイズして下さい。
my $hostname = "127.0.0.1"; # Name of server my $port = "80"; # Port on server my $address = "server-status/?auto"; # Server Status Address my $log_directory = "/var/log"; # Log Directory
※公開したものは、デフォルトで恐らく動くであろう状態にしています。
実行例
出力されるログはこんな感じです。ログファイルが無い場合はヘッダを入れるようにしました。
また、データが採取できない場合は0が入るようにしています。
# cat /var/log/20110110.server-status.log date,time,total_access,total_kbytes,uptime,req_per_sec,bytes_per_sec,bytes_per_req,busyservers,idleservers,waiting,starting_up,reading,sending,reading_keepalive,look_up_dns,closing,logging,finishing_gracefully,clean_up_idle,open_slot 2011/01/10,01:01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2011/01/10,01:02,140223,6025,53,2645.72,116408,43.9985,28,0,0,2,0,1,0,0,27,0,0,0,226 2011/01/10,01:03,326803,14042,118,2769.52,121856,43.999,32,0,0,2,0,4,0,0,27,1,0,0,222 2011/01/10,01:04,462158,19859,165,2800.96,123246,44.0014,45,1,1,2,0,1,0,0,44,0,0,0,208 2011/01/10,01:05,616680,26499,219,2815.89,123904,44.0017,29,1,1,1,1,1,0,0,27,0,0,0,225 2011/01/10,01:06,800586,34401,283,2828.93,124476,44.001,50,0,0,2,1,1,0,0,48,0,0,0,204 2011/01/10,01:07,915240,39328,324,2824.81,124296,44.0014,31,4,4,0,0,1,0,0,30,0,0,0,221 2011/01/10,01:08,1000049,42971,384,2604.29,114589,44.0001,1,9,9,0,0,1,0,0,0,0,0,0,246 2011/01/10,01:09,1000050,42971,444,2252.36,99104.3,44.0001,1,9,9,0,0,1,0,0,0,0,0,0,246 2011/01/10,01:10,1000051,42972,504,1984.23,87308.2,44.0011,1,9,9,0,0,1,0,0,0,0,0,0,246 2011/01/10,01:11,1000052,42972,564,1773.14,78020.1,44.001,1,9,9,0,0,1,0,0,0,0,0,0,246 2011/01/10,01:12,1000053,42972,624,1602.65,70518.2,44.001,1,9,9,0,0,1,0,0,0,0,0,0,246
今回の確認用に、Apache同梱の「ab」を使いました。
# /usr/local/httpd-2.2.17.80/bin/ab -n 1000000 -c 30 http://127.0.0.1/index.html This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 100000 requests Completed 200000 requests Completed 300000 requests Completed 400000 requests Completed 500000 requests Completed 600000 requests Completed 700000 requests Completed 800000 requests Completed 900000 requests Completed 1000000 requests Finished 1000000 requests Server Software: Apache/2.2.17 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: /index.html Document Length: 44 bytes Concurrency Level: 30 Time taken for tests: 350.418 seconds Complete requests: 1000000 Failed requests: 0 Write errors: 0 Total transferred: 296000000 bytes HTML transferred: 44000000 bytes Requests per second: 2853.73 [#/sec] (mean) Time per request: 10.513 [ms] (mean) Time per request: 0.350 [ms] (mean, across all concurrent requests) Transfer rate: 824.91 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.7 0 14 Processing: 2 10 143.8 9 38925 Waiting: 1 9 119.2 8 38925 Total: 2 10 143.8 9 38925 Percentage of the requests served within a certain time (ms) 50% 9 66% 10 75% 10 80% 10 90% 10 95% 11 98% 12 99% 12 100% 38925 (longest request)
定期的に実行する場合は cron の設定を行います。
以下は5分毎に実行する例です。
*/5 * * * * /usr/local/scripts/get_server_status.pl
今日はこんなところで。