Bash
MySQL
zabbix

【Zabbix】history_logのログをホスト/アイテムごとにログ出力

【作成した背景と機能】

監視システム更改直後、エラーが多発していた際に、
インフラ/開発/運用で手分けしてエラーへの対応をしなければ
なりませんでしたが、ZabbixWebGUIを確認できる端末数は
限られていたため、外部にエラーログを出力する必要性が生じました。

理想としては、以下の機能が欲しいとぼんやり考えていました。

 ・ホスト名かつアイテムごとにログファイルを出力
 ・ファイル名を見ただけでどのサーバのどのログかわかる
 ・期間指定可能(※ログ保存期間が許す限り)

Zabbixは下記種類のログをhistory_logテーブルへ
格納しているので、ここから上手く一括出力できないか思案しました。

 ・/var/log/messagesのアイテムで設定したエラーログ
 ・OracleやMySQL、SQL ServerなどのDB各種ログ
 ・WindowsのAPP/SYS/SECURITYログ
 ・その他、設定しているならあらゆるログデータ

【検証環境】

 ●Zabbixサーバ
 ・CentOS 7.4
 ・Zabbix 3.4.3(3.0.9でも大丈夫)
 ・MySQL 5.7.20

【利用するツールの紹介】

設定ファイルと本ツールの2つを使用して一括出力します。

◆logexport.txt
取得するヒストリログのリストをシェル内で作成し、
その結果を出力するテキストがこのファイルです。
中は以下のような感じです。

logexport.txt
28603   Zabbixs01       SNMP_Trap_fallback
28604   タスクPC       SNMP_Trap_linkDown

左から、アイテムID、ホスト名、アイテム名を
格納し、後ほど引数として利用します。
シェル内でこのテキストファイルは自動作成しますので、
用意しなくて大丈夫です。

◆dump_historylog.sh
本ツールです。実装した機能は上述したので省略します。

【dump_historylog.sh】

以下がシェルの内容です。

dump_historylog.sh
#!/bin/bash

###初期設定
OUT_DIR=/home/ToolAdmin/log
CUR_DIR=`dirname $0`

###MySQL設定
MY_CONF=/home/ToolAdmin/mysql.conf

###取得期間の設定
STIME=`date +%s -d '90 days ago'`
ETIME=`date +%s`

CON_FILE=logexport.txt

###取得ヒストリログリストを作成
mysql --defaults-extra-file=${MY_CONF} << _EOSQL_ | sort | uniq -c | sed -e 's/      1 //g' -e '/itemid/d' > $CUR_DIR/$CON_FILE
SELECT distinct
 i.itemid,
 h.host,
 i.name
FROM history_log hl
INNER JOIN items i ON hl.itemid = i.itemid
INNER JOIN hosts h ON i.hostid = h.hostid
_EOSQL_

###出力不可になる特殊文字列の排除
sed -i -e "s/[\|/|:|*|?|\"|<|>|\|]/-/g" "$CUR_DIR/$CON_FILE"

###history_log取得
while read LINE
do
ITEMID=`echo $LINE | awk '{print $1}'`
HOSTNAME=`echo $LINE | awk '{print $2}'`
INAME=`echo $LINE | awk '{print $3}'`
OUT_FILE=${HOSTNAME}_${INAME}_`date +%Y%m%d%H%M%S`.log
mysql --defaults-extra-file=${MY_CONF} << _EOSQL_ >> $OUT_DIR/$OUT_FILE
SELECT
 i.itemid 'アイテムID',
 h.name 'ホスト名',
 FROM_UNIXTIME(hl.clock) '日時',
 hl.severity 'Win深刻度',
 hl.source 'Winソース',
 hl.logeventid 'WinEVT_ID',
 hl.value 'エラー内容'
FROM history_log hl
INNER JOIN items i ON hl.itemid = i.itemid
INNER JOIN hosts h ON i.hostid = h.hostid
WHERE hl.clock BETWEEN ${STIME} AND ${ETIME}
ORDER BY hl.clock;
_EOSQL_
done < $CUR_DIR/$CON_FILE

実行すると下記のようなログが出てきます。
ホストかつアイテムごとにファイルが出力されるので、
大量のファイルが出力されます。あらかじめご注意ください。
キャプチャ.PNG

私の検証環境はしょぼいのでSNMPTrapのテストログしか出てきません!

あとはダウンロードして確認すれば終わりです。
もし全てのログをマージしたければ以下のコマンドを打てば良いかと思います。
※見出し行だけ消えてしまいますが。

command.
cat *.log | sed -e '/^アイテムID*/d' > AllMerge.log

【注意点や反省点】

・特殊文字処理について
 スクリプトの途中で特殊文字を削除している処理があります。
 これはアイテム名に特殊文字が入っていると出力エラーとなり失敗することを
 防ぐためです。しかしここが一点制限があり、アイテム名に空欄がある場合は
 一単語目までしかファイル名に反映してくれません。

 ここは直したいですがいい案が浮かばないので、とりあえずこれで。

・出力ファイルの区切り文字について
 今回はスペースで出力しています。
 カンマでもタブも考えましたが、ログ内カンマがある可能性もあるため、
 そのまま出力しています。

簡易に作成しましたのでカスタマイズしやすいと思います。
特定のアイテムだけ欲しいとか、見出しの名前がセンス悪いから変えるとか、
色々できると思いますので、ご活用頂ければ幸いです。

なにかありましたらコメントでお待ちしております。
※前の記事で編集リクエスト送ってくれた方ありがとうございました。

以上です。