ようへいの日々精進XP

よかろうもん

Rundeck のログを flunetd に流す Rundeck Logging Plugin を作ってみた

おはげようございます。

tl;dr

最近、個人的に Rundeck を触り始めている。

Rundeck の詳細については、以下の記事がとても参考になると思っているので、そちらをご一読頂くとして...

heartbeats.jp

Rundeck の中身を知る一環として Plugin について調べていたら Logstash にジョブの結果を流すプラグインが既に在ったので...

github.com

そちらをパクらせて参考にさせて頂いて、同様にジョブの結果を flunetd に流す Rundeck Plugin を作ってみた。

github.com

あくまでも作ってみただけなので色々と雑になってしまっているのはすいません。


Logging Plugin について

参考

プラグインの種類

以下の三種類の Logging プラグインを作成することが出来る。

  • Writer plugins

下図の通り Job の実行結果をログをストリームで書き出す。今回、作った Fluentd 用のプラグインはこの Write Plugin となる。

http://rundeck.org/docs/figures/log%20storage1.png

(出典:About Rundeck Logging

  • Reader plugins

下図の通りログファイルをストリームで読み込む。

http://rundeck.org/docs/figures/log%20storage2.png

(出典:About Rundeck Logging

  • Storage plugins

このタイプのプラグインに関しては具体的にどのような用途かちゃんと理解出来ていない。

http://rundeck.org/docs/figures/log%20storage3.png

(出典:About Rundeck Logging

Java か Groovy で実装する

Logging Plugin は Java と Groovy という言語で実装することが出来る。Java については特に言及は無い(言及するほどの知見は無い)が、Groovy に関しては JVM 上で動作する Java と親和性の高いスクリプト言語とのことで、Java よりは簡単に初められるのでは...(あくまでも個人的見解です...)という安易な気持ちでプラグイン作りに取り掛かった。

尚、Rundeck のプラグインには以下のような種類がある。(各プラグインの詳細についてはこちら。)

  • Node Executor Plugin
  • Workflow Step Plugin
  • File Copier Plugin
  • Logging Plugin
  • Notification Plugin
  • Resource Model Source Plugin
  • Model Format Parser and Generator Plugin
  • Orchestrator Plugin
  • Storage Converter Plugin
  • Storage Plugin

幾つかのプラグインに関しては Java や Groovy 以外にシェルスクリプトで実装出来るプラグインもある。但し、Logging Plugin について Java と Groovy のみとなる。

何はともあれサンプルコード

全く知見の無い自分がうんちくを書くよりも以下のサンプルを見て頂いた方が百万倍良いと思う。

github.com

以下、ザックリポイント。

  • com.dtolabs.rundeck.plugins.logging.StreamingLogWriterPlugin ライブラリをインポート
  • rundeckPlugin メソッドを利用
import com.dtolabs.rundeck.plugins.logging.StreamingLogWriterPlugin
rundeckPlugin(StreamingLogWriterPlugin){
    //plugin definition
}
configuration{
    //property definitions go here...
}
//
open { Map execution, Map config ->
    //open a stream for writing
    //return a map containing any context you want to maintain
    [mycounter: ..., mystream: ... ]
}
//
addEvent { Map context, LogEvent event->
   // write the event to my stream
}
//
close { Map context ->
    // close my stream
}

詳細はドキュメントをご一読を...。


rundeck-fluentd-plugin の使い方

インストール

インストールは FluentdPlugin.groovy を $RDECK_BASE/libext/ にコピーする。

$ sudo cp FluentdPlugin.groovy /var/lib/rundec/libext/

依存するライブラリの設置

とりあえず、以下のライブラリを設置することでプラグインが動作することを確認した。

$ sudo su -
# cd /var/lib/rundeck/bootstrap
# wget http://central.maven.org/maven2/org/msgpack/msgpack/0.6.12/msgpack-0.6.12.jar .
# cp /var/lib/rundeck/exp/webapp/WEB-INF/lib/javassist-3.17.1-GA.jar .

※この方法が正しいかは解らないので正しい方法がマジでしりたひ

設定ファイル

以下のファイルの末尾に追記する。

  • /etc/rundeck/rundeck-config.properties
rundeck.execution.logs.streamingWriterPlugins=FluentdPlugin
  • /etc/rundeck/framework.properties
framework.plugin.StreamingLogWriter.FluentdPlugin.port=24224
framework.plugin.StreamingLogWriter.FluentdPlugin.host=localhost
framework.plugin.StreamingLogWriter.FluentdPlugin.tag=rundeck.log
  • /etc/rundeck/project.properties
project.plugin.StreamingLogWriter.FluentdPlugin.port=24224
project.plugin.StreamingLogWriter.FluentdPlugin.host=localhost
project.plugin.StreamingLogWriter.FluentdPlugin.tag_prefix=rundeck.log

設定したら Rundeck のプロセスを再起動しておく。

fluentd の設定

お試しなので in_forward プラグインだけ。

<source>
  type forward
  port 24224
  bind 0.0.0.0
</source>

<match rundeck.**>
  type stdout
</match>

設定したら fluentd を以下の通り起動しておく。

$ fluentd -c test.conf -l debug.log &

ジョブを実行すると...

一分ごとに HelloWorld を Echo するジョブを走らせておくと...以下のようなログが debug.log に流れる。

2015-10-22 23:40:00 +0900 rundeck.log.hello-world: {"execution.loglevel":"INFO","execution.wasRetry":"false","execution.url":"http://xxx.xxx.xxx.xx:4440/project/hello-world/execution/follow/1389","execution.id":"fdf1cca5-e729-491b-a1fa-3d8fef373d46","execution.project":"hello-world","execution.username":"admin","execution.retryAttempt":"0","execution.user.name":"admin","execution.name":"hello-world","execution.serverUUID":null,"execution.group":null,"execution.execid":"1389","execution.serverUrl":"http://xxx.xxx.xxx.xx:4440/","event.stepctx":"1","event.step":"1","line":1,"datetime":1445524800447,"loglevel":"NORMAL","message":null,"eventType":"stepbegin"}
2015-10-22 23:40:00 +0900 rundeck.log.hello-world: {"execution.loglevel":"INFO","execution.wasRetry":"false","execution.url":"http://xxx.xxx.xxx.xx:4440/project/hello-world/execution/follow/1389","execution.id":"fdf1cca5-e729-491b-a1fa-3d8fef373d46","execution.project":"hello-world","execution.username":"admin","execution.retryAttempt":"0","execution.user.name":"admin","execution.name":"hello-world","execution.serverUUID":null,"execution.group":null,"execution.execid":"1389","execution.serverUrl":"http://xxx.xxx.xxx.xx:4440/","event.node":"localhost","event.stepctx":"1","event.user":"rundeck","event.step":"1","line":2,"datetime":1445524800458,"loglevel":"NORMAL","message":null,"eventType":"nodebegin"}
2015-10-22 23:40:00 +0900 rundeck.log.hello-world: {"execution.loglevel":"INFO","execution.wasRetry":"false","execution.url":"http://xxx.xxx.xxx.xx:4440/project/hello-world/execution/follow/1389","execution.id":"fdf1cca5-e729-491b-a1fa-3d8fef373d46","execution.project":"hello-world","execution.username":"admin","execution.retryAttempt":"0","execution.user.name":"admin","execution.name":"hello-world","execution.serverUUID":null,"execution.group":null,"execution.execid":"1389","execution.serverUrl":"http://xxx.xxx.xxx.xx:4440/","event.node":"localhost","event.stepctx":"1","event.user":"rundeck","event.step":"1","line":3,"datetime":1445524800869,"loglevel":"NORMAL","message":null,"eventType":"nodeend"}
2015-10-22 23:40:00 +0900 rundeck.log.hello-world: {"execution.loglevel":"INFO","execution.wasRetry":"false","execution.url":"http://xxx.xxx.xxx.xx:4440/project/hello-world/execution/follow/1389","execution.id":"fdf1cca5-e729-491b-a1fa-3d8fef373d46","execution.project":"hello-world","execution.username":"admin","execution.retryAttempt":"0","execution.user.name":"admin","execution.name":"hello-world","execution.serverUUID":null,"execution.group":null,"execution.execid":"1389","execution.serverUrl":"http://xxx.xxx.xxx.xx:4440/","event.stepctx":"1","event.step":"1","line":4,"datetime":1445524800870,"loglevel":"NORMAL","message":null,"eventType":"stepend"}
2015-10-22 23:40:00 +0900 rundeck.log.hello-world: {"execution.loglevel":"INFO","execution.wasRetry":"false","execution.url":"http://xxx.xxx.xxx.xx:4440/project/hello-world/execution/follow/1389","execution.id":"fdf1cca5-e729-491b-a1fa-3d8fef373d46","execution.project":"hello-world","execution.username":"admin","execution.retryAttempt":"0","execution.user.name":"admin","execution.name":"hello-world","execution.serverUUID":null,"execution.group":null,"execution.execid":"1389","execution.serverUrl":"http://xxx.xxx.xxx.xx:4440/","ending":true,"totallines":4,"message":"Execution null finished."}

ということで...

作る過程で得た知見

  • Groovy って Ruby に似た側面もありそう

ということで、以下の記事が参考になる。

qiita.com

どの辺が具体的に似てるとかには言及する知見は無いが Ruby っぽい書き方も出来るだということを感じた。

  • MessagePack と Fluentd について

例えば、[tag, time, record] という配列を以下のようにしてシリアライズして Fluentd に投げる感じ。

MessagePack.pack([tag, time, record])

Enjoy Rundeck

Rundeck 道の入り口にやっと立てたのでこれからも精進したい。

以上。