Windowsのプロセス単位のCPU使用率アラートをfluentdを使ってやってみる

fluentdにいつの間にかWindowsユースケースが載っていました。気づくの遅すぎ。
 http://docs.fluentd.org/ja/articles/windows
ということでレッツトライします。
お題はWindows側の特定プロセスのCPU使用率が●%を越えたらアラート。
ユースケースに則ってWindows側にnxlogをインストールして、fluentd側で type syslog で受けるところまでは進めます。
受け側のfluentd側はセットアップで楽するためにtd-agentを入れました。
なんとか目的のものはできましたが、なんか非効率な気がしているので何だかなぁ…という感じです。

Windows側で使うもの(Linux側のfluentdはなくて良いよね…)

PsList http://technet.microsoft.com/en-us/sysinternals/bb896682
nxlog http://nxlog.org/download

大雑把な構造
pslist -s でファイルに pslist の結果を出力
nxlog で pslist の結果を fluentd に飛ばす
fluentd の syslog で受ける
filtered で必要なプロセスに絞る
notifier で閾値設定とアラート出力
nxlog.conf
 define ROOT C:\Program Files (x86)\nxlog
 Moduledir %ROOT%\modules
 CacheDir %ROOT%\data
 Pidfile %ROOT%\data\nxlog.pid
 SpoolDir %ROOT%\data
 LogFile %ROOT%\data\nxlog.log
 <Extension syslog>
   Module      xm_syslog
 </Extension>
 <Extension json>
   Module      xm_json
 </Extension>
 <Input in>
   Module im_file
   File "D:\work\winfluent\srclog\log.txt"
   SavePos TRUE
   InputType LineBased
 </Input>
 <Processor t>
   Module pm_transformer
   OutputFormat syslog_bsd
   Exec $Message=(": "+$raw_event);
 </Processor>
 <Output out>
   Module om_tcp
   Host xxx.xxx.xxx.xxx
   Port 5140
 </Output>
 <Route r>
   Path in => t => out
 </Route>
fluentd側追加プラグイン
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-filter
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-mail
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-notifier
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-parser
/usr/lib64/fluent/ruby/bin/gem install fluent-plugin-rewrite-tag-filter
td-agent.conf(syslogで受けるところからの部分のみ。最終的にはmail通知。)

firefoxプロセスのCPU使用率5%/10%以上でのアラート
IdleのCPU使用率50%/20%以下でのアラート(マシン全体のCPU使用率の代わりです)

# サンプルそのまま
<source>
  type syslog
  protocol_type tcp
  port 5140
  tag winlog
</source>

# filterプラグインで以降に流す部分の量を減らすためにプロセス名でフィルタします。
# syslog で受けたものをそのまま受けてフィルタするため、正規表現パターンで行います。
<match winlog.**>
  type filter
  all deny
  allow message: /firefox/, message: /Idle/
</match>
#<match filtered.**>
#  type stdout
#</match>

# この後 parse に入力すると syslog で受けた key=host が無くなるため、
# ここで rewrite_tag_filter を使ってホスト名をタグ部分に移動させます。
<match filtered.**>
  type rewrite_tag_filter
  rewriterule1  host  ^(.+)$  filterrewrited.$1.${tag}
  remove_tag_prefix filtered
</match>

# parse で message 内容に key 付けして、notifier で使う target_keys を作ります。
<match filterrewrited.**>
  type parser
  remove_prefix filterrewrited
  add_prefix winproc
  format /^(?<Name>[^ ]* +\d+) +(?<Cpu>\d+) +(?<Thd>\d+) +(?<Hnd>\d+) +(?<Priv>\d+) +(?<CpuTime>.+) +(?<ElapsTime>.+)$/
  key_name message
  suppress_parse_error_log true
</match>
#<match winproc.**>
#  type stdout
#</match>

# notifier のデフォルトアラート出力だとプロセス名などが抜けてしまうので、
# rewrite_tag_filter でタグ側に移動させます。今回はプロセス名とPID。
# ついでに、message のパースの際プロセス名を key にする方法がちょっと探しきれずにタイムオーバしたため
# 暫定でプロセス名をタグの先頭に配置することで、後の notifier の match にプロセス名を使えるようにして
# プロセスごとの閾値を設定できるようにします。
<match winproc.**>
  type rewrite_tag_filter
  rewriterule1  Name  ^([^ ]*) +(\d+)$  $1.$2.${tag}
  remove_tag_prefix winproc
</match>

# プロセス名ごとに match ルールで notifier で閾値設定。
# 本当は <def> 内の target_keys を プロセス名_Cpu とかにして、記述できるようが綺麗だと思ってる…。
<match firefox.**>
  type notifier
  <def>
    pattern     firefox
    check       numeric_upward
    warn_threshold 5
    crit_threshold 10
    target_keys Cpu
  </def>
</match>
<match Idle.**>
  type notifier
  <def>
    pattern     Idle
    check       numeric_downward
    warn_threshold 50
    crit_threshold 20
    target_keys Cpu
  </def>
</match>

# 最終的にはメール通知とかIRCに出すとか。もうお好みで。
<match notification.**>
  type stdout
#  type     mail
#  host     localhost
#  port     25
#  from     FROM
#  to       TO
#  subject  fluentd notification
#  out_keys pattern,target_tag,target_key,level,value,message_time
</match>
Windows側でのテストキック
D:\work\winfluent\PSTools
pslist.exe -s 100 >> ..\srclog\log.txt
サンプル出力
2014-05-04 20:26:54 +0900 notification: {"pattern":"Idle","target_tag":"Idle.0.desktop-PC.winlog.user.notice","target_key":"Cpu","check_type":"numeric_upward","level":"crit","threshold":10.0,"value":91.0,"message_time":"2014-05-04 03:15:51 +0900"}
改善したいもの

本当は notifier の target_keys でプロセス名を指定して閾値を設定したいのだけど、その場合は送られてきた message 内のプロセス名を key に設定しないといけない。
ざっくりプラグインリストを見ていたけど、ちょっと目的に合うものが簡単には見つからなかったので rewrite_tag_filter を使ってプロセス名やホスト名をタグの方に持ってきて notification 出力を調整。
実運用時には、オリジナルログの保全のために type syslog で受けたものをファイルコピーする部分も別に必要。
win側では pslist の定期実行とログローテ用のスクリプト作成が必要。
1時間単位での min/max/avg も出したくなってくる。
メモ:fluent-plugin-forestとfluent-plugin-datacalculator