ようへいの日々精進XP

よかろうもん

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

tl;dr

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

参考

www.elastic.co

github.com

雑なうんちく

logstash プラグインの種類は?

実装は?

雛形生成

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

/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.99"
-  s.add_runtime_dependency "logstash-codec-plain"
+  s.add_runtime_dependency "logstash-core", ">= 2.0.0", "< 3.0.0"
+  s.add_runtime_dependency "mackerel-client"
   s.add_development_dependency "logstash-devutils"
+  s.add_development_dependency "mackerel-client"

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

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

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

class LogStash::Outputs::Mackerel < LogStash::Outputs::Base
  config_name "mackerel"
  config :api_key, :validate => :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-rubypost_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 1023 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 {
      #
      # /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
}

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

f:id:inokara:20161023091514p:plain

よし。

以上

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