agentのmoduleを書いてみる
Pandora FMSは監視対象のサーバにAgentを置くこともできます。このAgentはmoduleを実行して、その結果をServerに対して送ります。あ、なんせ使い出して日が浅いものでこの"module"という用語が適切かどうかはわかりませんが、まあ許してください。
このmoduleは普通のスクリプトです。標準出力に出した数字や文字列がそのままserverに送られます。
なお、スクリプトの内部にwarningやcritialの判定を入れる必要はありません。その判定はserver側で行います。
ウェブモニタリング
なんかウェブモニタリングはエンタープライズ版だけだそうなので、軽く書いてみました。
curlには --write-out という、かかった時間を出してくれるオプションがあります。
module_begin module_name http_time_total module_type generic_data module_exec curl --output /dev/null --write-out "%{time_total}" --silent http://somewhere.example.co.jp/path/ module_description time_total to somewhere in milli sec module_end
manをみれば、time_total以外にもいろいろありますので、必要に応じて変えるといいと思います。
PostgreSQLのアクセス統計
PostgreSQLは pg_stat_tables で各種統計情報が取れます。これを使ってPostgreSQLへのアクセスの統計を取ります。
pg_stat_user_tables から取れる情報は積算値なので、軽く適当なスクリプトを書いて単位時間(デフォルトでは300秒)あたりのアクセスにならします。
リモートのインスタンスから取る場合はpsqlの引数を適当に変えてください。
#!/usr/bin/env sh DB=database TABLE=target_table HISTFILE=/tmp/pandora_pg_idx_scan_count.tmp if [ ! -e $HISTFILE ] then echo "0" > $HISTFILE fi prev=`cat $HISTFILE` now=`psql -tA -c "select idx_scan from pg_stat_user_tables WHERE relname = '$TABLE';" $DB` value=`expr $now - $prev` if [ $value -le 0 ] then echo "0" else echo $value fi echo $now > $HISTFILE
pandora_agent.confにはこんな感じで書きます。
module_begin module_name scan_count module_type generic_data module_exec /path/to/pandora/etc/pandora/plugins/pg_scan_count.sh module_max 100 # ここは好きに変えてください module_min 0 module_description Table index scan count module_end
これは idx_scan の数ですが、pg_stat_user_tables にはcommit数とかロールバック数とかも格納されているので適宜変更するといいと思います。
なお、module_maxは最大値です。自動的に判定してくれるので指定する必要は本当はないのですが、いろいろ試してたら指定しないといけなくなったのでしています。なお、 module_postprocess という設定を入れると、数値を指定した倍率でかけてくれます。 1024 なら1024倍、0.000976563なら 1/1024 にしてくれますので、適宜調整するといいと思います。
tomcatのfree memoryを取る
tomcatのmanagerを使ってメモリの空き容量を%表示で出します。tomcatが出す情報はXMLかHTMLのようなので、shellで書くのはあきらめてpythonを使いました。minidomを使っているので、試してませんが python 2.4 でも動くはずです。
なお、当たり前ですが事前にmanagerの認証設定をしておく必要があります。
#!/usr/bin/env python # -*- coding: utf-8 -*- import urllib import urllib2 from xml.dom.minidom import parseString # for 2.4, use minidom URL = "http://localhost:8080/manager/status?XML=true" USER = "user" PASS = "password" def get_xml(url, user, passwd): passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, url, user, passwd) auth_handler = urllib2.HTTPBasicAuthHandler(passman) opener = urllib2.build_opener(auth_handler) urllib2.install_opener(opener) f = urllib2.urlopen(url) xml = f.read() return xml def get_jvm_memory(dom): for n in dom.getElementsByTagName("memory"): return {"max": float(n.attributes["max"].value), "free": float(n.attributes["free"].value)} if __name__ == '__main__': xml = get_xml(URL, USER, PASS) dom = parseString(xml) mem = get_jvm_memory(dom) print((mem["free"] / mem["max"]) * 100 )
pandora_agent.confにはこんな感じで書きます。
module_begin module_name tomcat_free_mem module_type generic_data module_exec python /path/to/pandora/etc/pandora/plugins/tomcat_free_mem.py module_description Tomcat free memory in MB module_end
これだけです。
Agent側で動作
module_condition <評価式> <コマンド>
Pandora FMSのAgentは、module_conditionという値を設定することで、モジュールが特定の値を返す場合に指定したコマンドを実行できます。
- > [値]: モジュールの値が指定された値よりも大きい場合
- < [値]: モジュールの値が指定された値よりも小さい場合
- = [値]: モジュールの値が指定された値と同じ場合
- != [値]: モジュールの値が指定された値と異なる場合
- =~ [正規表現]: モジュールの値が指定された正規表現にマッチする場合
- (値, 値): モジュールの値が指定された値の範囲の場合
また、以下のように、同一のモジュールに複数の条件を設定することも可能です。
module_begin module_name condition_test module_type generic_data module_exec echo 2.5 module_condition (1, 3) script_1.sh module_condition > 5.5 script_2.sh module_end
module_conditionの例を示します。
重複プロセスがあったらkillする
module_begin module_name MyProcess module_type generic_data module_exec tasklist | grep MyProcess | wc -l module_condition > 2 taskkill /IM MyProcess* /F module_end
Logが大きくなったら削除する
module_begin module_name PandoraLogSize module_type generic_data module_exec ls -la "c:\Archivos de programa\pandora_agent\pandora_agent.log" | gawk "{ print $5 }" module_condition > 10000 del "c:\Archivos de programa\pandora_agent\pandora_agent.log" module_end
Spoolerが落ちてたら再起動する
module_begin module_name Service_Spooler module_type generic_proc module_service Spooler module_condition = 0 net start Spooler module_end
こんな感じで
なにか異常があったらメールでアラートを飛ばしつつ、自動的に出来る範囲であれば自力で復旧する、ということが簡単に書けるようです。