はじめに
Nagiosの監視状況を確認したいとき、通常はWebブラウザでダッシュボードを開いて確認したい場合があります。ですが他のスクリプトと組み合わせて何かしたいなという場合にブラウザベースでデータを取得して整形したりするのが手間だったりします。
「コマンドラインからサクッとステータスが取れたらな」と思って調べた結果、2つの便利スクリプトができたのでまとめておきます。
環境
- Nagios Core 3.2.3(CentOS 6系)
- Nagios CGI: /usr/lib64/nagios/cgi/
- ログディレクトリ: /var/log/nagios/
注意: Nagios Core 4系以降であれば statusjson.cgi というJSON APIが使えるが、3系にはない。今回はそれが使えない環境での話。同じコマンドでCGIのパスは違うがNagios Core 4系でも使えることは確認済み
アラート履歴の取得
ログファイルの構造
Nagiosのログはこんなパスに格納されています。
/var/log/nagios/nagios.log # 現在のログ
/var/log/nagios/archives/nagios-MM-DD-YYYY-00.log # アーカイブ(日次ローテーション)
アーカイブのファイル名は nagios-05-25-2026-00.log のように日付が入っているので、直近30日分のファイルを絞り込めます。
ログの中身はこんな形式。タイムスタンプはUNIXタイム。
[1778080216] SERVICE ALERT: example.com;SMTP;CRITICAL;SOFT;1;接続を拒否されました
このままだと日時がわかりにくいので date -d @タイムスタンプ で変換して人間が読める形に整形します。
スクリプト
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw(strftime);
sub get_nagios_alerts {
my ($hostname) = @_;
# 直近30日分のアーカイブファイルを取得
my @files = `find /var/log/nagios/archives/ -name "nagios-*-*.log" -mtime -30`;
push @files, "/var/log/nagios/nagios.log\n";
chomp @files;
for my $file (sort @files) {
open(my $fh, '<', $file) or next;
while (<$fh>) {
next unless /\Q$hostname\E/;
next unless /ALERT/;
next if /;OK;/;
if (/\[(\d+)\] (.*)/) {
my ($ts, $body) = ($1, $2);
my $dt = strftime('%Y-%m-%d %H:%M:%S', localtime($ts));
print "$dt $body\n";
}
}
close($fh);
}
}
my $hostname = $ARGV[0] or die "Usage: $0 \n";
get_nagios_alerts($hostname);
/usr/local/bin/get_nagios_alerts として保存して chmod +x しておきます。
実行例
$ /usr/local/bin/get_nagios_alerts example.com 2026-05-08 12:30:16 SERVICE ALERT: example.com;SMTP;CRITICAL;SOFT;1;接続を拒否されました 2026-05-11 08:10:06 SERVICE ALERT: example.com;POP;CRITICAL;SOFT;1;接続を拒否されました 2026-05-19 03:02:20 SERVICE ALERT: example.com;SUBMISSION;CRITICAL;SOFT;1;(Service Check Timed Out) 2026-05-19 03:04:20 SERVICE ALERT: example.com;POP;CRITICAL;SOFT;1;CRITICAL - Socket timeout after 30 seconds
現在ステータスの取得
まずcurlを試した
最初は単純に curl でWebUIのHTMLを取得してパースしようとしました。
curl -s -u nagiosadmin:password \ "http://nagios.example.com/nagios/cgi-bin/status.cgi?host=example.com" \ | grep -A3 'statusOk\|statusCritical'
一応動きますが、HTML構造がネストしていてパースが面倒だし、認証情報をコマンド履歴に残すのはどうかなという感じです。
CGIをローカルから直接呼ぶ
Nagiosの各CGIは /usr/lib64/nagios/cgi/ (Nagios4系は /usr/lib64/nagios/cgi-bin/) に実行ファイルとして置かれています。試しに直接実行してみると:
$ /usr/lib64/nagios/cgi/status.cgi getcgivars(): Unsupported REQUEST_METHOD -> '' In order to do that, you need to set the REQUEST_METHOD environment variable to either "GET", "HEAD", or "POST".
環境変数で REQUEST_METHOD や QUERY_STRING を渡せばいいらしいということがわかります。実際に試すと動きました。
REQUEST_METHOD=GET \QUERY_STRING="host=example.com" \ REMOTE_USER=nagiosadmin \ /usr/lib64/nagios/cgi/status.cgi
HTMLが出力されるので、あとはPerlでパースするだけ。ネットワーク越しのHTTP通信もBasic認証も不要なので、ローカルで動かす用途にはこちらの方がクリーンですね。
スクリプト
#!/usr/bin/perl use strict; my $hostname = $ARGV[0] or die "Usage: $0\n"; my $html = `REQUEST_METHOD=GET QUERY_STRING="host=$hostname" REMOTE_USER=nagiosadmin /usr/lib64/nagios/cgi/status.cgi`; while ($html =~ /service=[^>]+>([^<]+)<\/A>.*? ([^<]+)<\/TD>.*? ]*>[^<]+<\/TD>.*? ]*>[^<]+<\/TD>.*? ]*>[^<]+<\/TD>.*? ]*valign[^>]*>([^<&]+)/gsi) { my ($name, $status, $info) = ($1, $2, $4); $info =~ s/^\s+|\s+$//g; printf "%-15s %-12s %s\n", $name, $status, $info; } /usr/local/bin/nagios_status として保存します。
実行例
$ /usr/local/bin/nagios_status example.com DISK OK SNMP OK - 57 FTP OK FTP OK - 0.028 second response time on port 21 HTTP1 OK HTTP OK: HTTP/1.1 200 OK - 203 bytes in 0.030 second response time MAILDELAY OK delay OK - 0.54 sec, threshold = 600 sec PING OK PING OK - Packet loss = 0%, RTA = 0.99 ms POP OK POP OK - 0.027 second response time on port 110 SMTP OK SMTP OK - 0.037 sec. response time SSH OK SSH OK - OpenSSH_5.3 (protocol 2.0) SUBMISSION OK SMTP OK - 0.037 sec. response timeまとめ
作成した2つのコマンド:
コマンド 用途 nagios_status <hostname> ホストの現在のサービス状態を一覧表示 get_nagios_alerts <hostname> 直近30日分のアラート履歴を表示 障害通報が来たときに get_nagios_alerts でいつ何が起きたかを把握し、nagios_status で今の状態を確認するという使い方が便利ですね。
あるいは月のレポートを作成したい場合にも使えると思います。
Nagios 4系以降なら statusjson.cgi を使ったほうがパースも楽でおすすめですが、古い環境にはこの方法が使えます。同じく古いNagios環境で困っている人の参考になれば。


