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
こんな感じで

なにか異常があったらメールでアラートを飛ばしつつ、自動的に出来る範囲であれば自力で復旧する、ということが簡単に書けるようです。