tl;dr

logstash を理解するあたってプラグイン作ってみることにした。

参考


www.elastic.co

mackerel-client-ruby - Mackerel client implemented by Ruby

github.com

雑なうんちく

logstash プラグインの種類は?

実装は?

  • logstash は JRuby で実装されている
  • プラグインは Ruby で実装する

雛形生成

プラグイン作成にあたって雛形を生成するコマンドが用意されている。

/opt/logstash/bin/logstash-plugin generate --type input --name oreno_input --path /path/to/plugins/
/opt/logstash/bin/logstash-plugin generate --type output --name oreno_output --path /path/to/plugins/
/opt/logstash/bin/logstash-plugin generate --type filter --name oreno_filter --path /path/to/plugins/
/opt/logstash/bin/logstash-plugin generate --type codec --name oreno_codec --path /path/to/plugins/

アウトプットプラグインチュートリアル

何を作るか

Mackerel にデータを飛ばすプラグインを作ってみる。

実装、検証の環境

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"

$ java -version
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-3ubuntu1~16.04.1-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

$ /opt/logstash/bin/logstash --version
logstash 2.4.0

雛形作成

/opt/logstash/bin/logstash-plugin generate --type output --name mackerel --path ./
 Creating ./logstash-output-mackerel
         create logstash-output-mackerel/logstash-output-mackerel.gemspec
         create logstash-output-mackerel/Rakefile
         create logstash-output-mackerel/DEVELOPER.md
         create logstash-output-mackerel/CONTRIBUTORS
         create logstash-output-mackerel/CHANGELOG.md
         create logstash-output-mackerel/LICENSE
         create logstash-output-mackerel/spec/outputs/mackerel_spec.rb
         create logstash-output-mackerel/lib/logstash/outputs/mackerel.rb
         create logstash-output-mackerel/Gemfile
         create logstash-output-mackerel/README.md

logstash-output-mackerel.gemspec を修正

プラグインの詳細や依存する Gem を記載する。

--- /tmp/logstash-output-mackerel/logstash-output-mackerel.gemspec      2016-10-23 08:34:50.927361142 +0900
+++ logstash-output-mackerel.gemspec    2016-10-23 08:37:28.224957272 +0900
@@ -1,24 +1,25 @@
 Gem::Specification.new do |s|
-  s.name          = 'logstash-output-mackerel'
-  s.version       = '0.1.0'
-  s.licenses      = ['Apache License (2.0)']
-  s.summary       = 'TODO: Write a short summary, because Rubygems requires one.'
-  s.description   = 'TODO: Write a longer description or delete this line.'
-  s.homepage      = 'TODO: Put your plugin''s website or public repo URL here.'
-  s.authors       = ['']
-  s.email         = 'inokara@gmail.com'
-  s.require_paths = ['lib']
+  s.name = 'logstash-output-mackerel'
+  s.version         = "0.0.1"
+  s.licenses = ["Apache License (2.0)"]
+  s.summary = "foo."
+  s.description     = "bar."
+  s.authors = ["kappa"]
+  s.email = "inokara@example.com"
+  s.homepage = "http://example.com"
+  s.require_paths = ["lib"]

(snip)

   # Gem dependencies
-  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "= 2.0.0", "

lib/logstash/outputs/mackerel.rb に処理を書く

エラー処理等はひとまず無し。

# encoding: utf-8
require "logstash/outputs/base"
require "logstash/namespace"

class LogStash::Outputs::Mackerel  :string, :required => true
  config :service_name, :validate => :string, :required => true

  public
  def register
    require 'mackerel/client'
    @mackerel = Mackerel::Client.new(:mackerel_api_key => @api_key)
  end

  public
  def receive(event)
    metrics = [{'name' => event.get('host'), 'time' => event.get('timestamp').to_i, 'value' => event.get('value')}]
    @mackerel.post_service_metrics(@service_name, metrics)
  end
end
  • config_name にはプラグイン名を定義
  • config には logstash の設定ファイル内に記載するパラメータやパラメータのタイプを記載(今回は api_keyservice_name を定義)
  • register メソッドは initialize メソッドのように利用する(今回は Mackerel への接続クライアントを作成している)
  • receive メソッドは event に含まれているデータを次の処理に渡す(今回は mackerel-client-ruby の post_service_metrics メソッドを利用して Mackerel にデータをポストする)

尚、receive メソッドに渡される引数 eventLogStash::Event というクラスとなっているので、各要素については以下のように get メソッドを利用した。

metrics = [{'name' => event.get('host'), 'time' => event.get('timestamp').to_i, 'value' => event.get('value')}]

Gem をビルドする

cd logstash-output-mackerel
gem build logstash-output-mackerel.gemspec

カレントディレクトリに gem ファイルが生成される。

$ ls -l *.gem
-rw-rw-r-- 1 kappa kappa 7680 10月 23 08:54 logstash-output-mackerel-0.0.1.gem

ビルドした Gem をインストール

cd logstash-output-mackerel
sudo /opt/logstash/bin/plugin install logstash-output-mackerel-0.0.1.gem

動かしてみる

logstash 設定

  • input プラグインに exec プラグインを利用する(exec プラグインは command で指定したコマンドを実行して結果をルーティングする)
  • filter プラグインに grok プラグインを利用して input プラグインから渡されたデータを整形する(詳細は → https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html
  • output プラグインにデバッグ用に stdout プラグインと今回作成した Mackerel プラグインを指定する
input {
  exec {
      #
      # /tmp/test.sh
      # echo $(date +%s) ${RANDOM}
      # 
      # 60 秒毎に /tmp/test.sh を実行する
      #
      command => "bash /tmp/test.sh"
      interval => 60
  }
}

filter {
  grok {
    # 
    match => [ "message", "%{NUMBER:timestamp}\s*%{NUMBER:value:int}"]
  }
  date {
    match => [ "timestamp", "UNIX" ]
  }
}

output {
  stdout { codec => rubydebug }
  mackerel { 
    api_key => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    service_name => 'hogehoge'
  }
}

今回は設定ファイル名を demo.conf として保存しておく。

実行

以下のように logstash を実行する。

/opt/logstash/bin/logstash -f demo.conf

以下のように出力される。

Settings: Default pipeline workers: 4
Pipeline main started
{
       "message" => "1477181478 7945\n",
      "@version" => "1",
    "@timestamp" => "2016-10-23T00:11:18.000Z",
          "host" => "tpX1-Carbon",
       "command" => "bash /tmp/test.sh",
     "timestamp" => "1477181478",
         "value" => 7945
}
{
       "message" => "1477181538 23429\n",
      "@version" => "1",
    "@timestamp" => "2016-10-23T00:12:18.000Z",
          "host" => "tpX1-Carbon",
       "command" => "bash /tmp/test.sh",
     "timestamp" => "1477181538",
         "value" => 23429
}

しばらく放置しておくと...
20161023091514

よし。

以上

  • 若干だけど logstash の挙動を理解することが出来た
  • 思ったりよりも簡単にプラグインを実装することが出来た

元記事はこちら

logstash のアウトプットプラグイン作成チュートリアル