logstashのRuby filterでJAVAを呼び出す

logstashではRuby filterで色々できそうですが、業務ではJAVAがメインのため、なんとかJAVAでfilterを制御できないか模索してみました。

なんとか動いたので、こういう方法もあるんだという感じで見れもらえれば。

構成

podman version 3.0.0
elasticsearch 7.10.1
Kibana 7.10.1
logstash 7.11.1

20190524_log.csv
JRubyTest.jar
sample.conf
sample_ruby_filter.rb

logstash実行方法

動作検証中は以下のように-rを付与すると、sample.confが変わるたびにLogstashが設定を自動的にリロードし、再度動いてくれるため検証が楽です。

/usr/share/logstash/bin/logstash -r -f ./sample.conf

logstashの設定ファイル

input {
 file {
   path => ["/opt/20190524_log.csv"]
   sincedb_path => "/dev/null"
   start_position => "beginning"
  }
}
filter {
  ruby {
    path => "/opt/sample_ruby_filter.rb"
    script_params => {
      "source_field" => "1234567890"
    }
  }
}
output {
  stdout {
    codec => rubydebug
  }
}

filterのpathでrubyスクリプトを記載したファイルパスを設定します。

script_params部分はrubyスクリプトへのパラメータを渡せるようなので記載しましたが、今回は特に使いません。

Rubyスクリプト JAVA呼び出し

require 'java'
require './JRubyTest.jar'

import 'logstash_jruby.JRubyTest'

def register(params)
 #ここはlogstash起動時に1度しか呼ばれない模様。
 #なのでJAVAの初期化系とか1回だけ実施したい場合に使えると思われる
end

#eventはLogStash::Eventというクラスだった
def filter(event)
  #ここは確認用に記載しているだけで記載不要
  puts event.class

  test = JRubyTest.new
  test.exe(event)

  return [event]
end

puts event.classでeventのクラスを確認したところ、LogStash::Eventというクラスでした。これを後でJAVAのほうで使います。

たったこれだけの記載で、logstashのイベントをJAVAのほうで制御できるようになります。JAVAをメインに使っているので、Rubyを覚えなくてよくて助かります。

コンパイル時にlogstash-core.jarが必要なため、logstash環境から

/usr/share/logstash/logstash-core/lib/jars/logstash-core.jar

を持ってきて、クラスパスへ追加してください。

JAVAでlogstashのイベントを制御

package logstash_jruby;

import org.logstash.Event;
import org.logstash.ext.JrubyEventExtLibrary.RubyEvent;

public class JRubyTest {
	public JRubyTest() {
		System.out.println("--JRubyTest constructor--");
	}
	
	public void exe(RubyEvent rbe) {
		
		Event event = rbe.getEvent();
		System.out.println(event.getField("message").toString());
		
		event.setField("message", "testtest");
	}
}

JAVA側で

public void exe(RubyEvent rbe) {

にてlogstashのイベントを受け取ることができます。

System.out.println(event.getField(“message”).toString());

にてイベントの中身messageも取得でき、

event.setField(“message”, “testtest”);

のようにすることでmessageの中身を書き換えることができます。

inputで読み込むファイルの中身

Date,Level,ErrorMessage,UserId
2019-05-24 10:00:00,INFO,Success,1
2019-05-24 11:00:00,WARN,xxxxxxxx,3

logstashの実行結果

LogStash::Event
--JRubyTest constructor--
Date,Level,ErrorMessage,UserId

LogStash::Event
--JRubyTest constructor--
2019-05-24 10:00:00,INFO,Success,1

LogStash::Event
--JRubyTest constructor--
2019-05-24 11:00:00,WARN,xxxxxxxx,3

{
          "path" => "/opt/20190524_log.csv",
      "@version" => "1",
       "message" => "testtest",
    "@timestamp" => 2021-02-23T09:26:02.010Z,
          "host" => "1777439e2c63"
}
{
          "path" => "/opt/20190524_log.csv",
      "@version" => "1",
       "message" => "testtest",
    "@timestamp" => 2021-02-23T09:26:02.012Z,
          "host" => "1777439e2c63"
}
{
          "path" => "/opt/20190524_log.csv",
      "@version" => "1",
       "message" => "testtest",
    "@timestamp" => 2021-02-23T09:26:02.012Z,
          "host" => "1777439e2c63"
}

JAVAのJRubyTestクラスでmessageの中身を書き換えましたが、logstash側でもtesttestになっていることが確認できました。