2016年6月5日日曜日

2016年1月4日月曜日

logstashをWindowsで使う

最近elasticsearchが面白そう。あとログ収集でfluentdを使っているけど、logstashも気になるところ。 ということで、使ってみる。

ここを参考にさせてもらいました(途中まではほぼ一緒)。
http://qiita.com/qtwi/items/98c1184a8a6ce6e2a5e7

やってみることは、fluentdで実装済みなのですが、あるcsvファイルを読み取り、mongodbに保存する。という内容。環境は以下の通り

・ Windows8.1(x64)
・ Java 7u79(JRubyを使う) ※javaはインストール済み
・ logstash 2.1.1
・ mongodb v3.2.0-rc4

0.準備
 
 javaがセットアップされていること。JAVA_HOMEも忘れずにセットアップ。
 mongodbがセットアップされていること。

1.logstash のインストール

  ここからインストーラをダウンロードする。
  https://download.elastic.co/logstash/logstash/logstash-2.1.1.zip
  し、中のフォルダを適当な場所にコピーする。
  ここでは、「C:\logstash-2.1.1」にコピー。

2.pluginのインストール

  今回使うpluginは以下の通り。
  1.ファイルを読み取るに、logstash-input-fileを使う
   2.読み取ったログのデータにfield名をつけるのに、logstash-filter-csvを使う
    3.読み取ったログの数値型データに型を割り当てるのに、logstash-filter-mutateを使う
    4.読み取ったログのデータに日付型を割り当てるのに、logstash-filter-dateを使う
    5.mongodbに入れるのに、logstash-output-mongodbを使う
インストールしてみる。pluginに関するコマンドは、以下の通り。
$ cd C:\logstash-2.1.1\bin

  インストール済みのpluginを表示する。

$ plugin list

  今回のpluginのうち、
  ・logstash-input-file
  ・logstash-filter-csv
  ・logstash-filter-mutate
  ・logstash-filter-date
  はデフォルトでインストールされていることがわかる。
  あとはmongodb。

$ plugin install logstash-output-mongodb

  これでインストールができる。インストール済みのoutputプラグインを見るには、

$ plugin list --group output
  で絞って見れる。plugin名の一部で検索することもできる

$ plugin list mongodb

インストールができていることを確認。

  ※proxy環境下の場合は以下の設定をする
$ export HTTP_PROXY=http://[proxy server]:[proxy port]

3.設定ファイルの作成

 作成するにあたっての想定は以下の通り。

 ・サンプルに使うデータは"c:\test\test.csv"とする
 ・データの中身は以下の通り
time,hostname,object,metric ,value,data1,data2,data3,data4,data5
2015/11/21 00:00:05,server1,object1,metric1,0.13,201511,21,00,00,05
 ・上記のデータのうち、data1まで取り込んで、data2-5は取り込まない
 ・フィールドの"time"はdate型、"value"はfloat型、残りはstring型とする
 ・時間のフィールド名は"time"とする(@timestampではない)

 これで設定をすると、
  
input {
  file{
    path => ['C:\test\test.csv']    # input用ファイル
    start_position => beginning     # ファイルを最初からチェックする
  }
} filter {
  csv {
    columns =>[      # フィールド名
      "time",
      "hostname",
      "object",
      "metric",
      "value",
      "data1"
    ]
    separator => "," # 区切り文字はカンマ
  }
  mutate {
    convert => {
      "value" => "float"    # フィールド"value"の型をfloat型に変換
    }
  }
  date {
    match => [ "time","YYYY/MM/dd HH:mm:ss"]     # フィールド"time"の値をdate型に変換
    timezone => "Asia/Tokyo"                     # タイムゾーンを日本に。
    target => "time"                             # 変換後の値をフィール"time"にセット。デフォルトは"@timestamp"
  }
} output {
    stdout{}               # 確認のために標準出力に出力
    mongodb {    # mongodbに入れる
      codec => plain
      collection => "windows"             # collection名
      database => "logstash"              # database名
      isodate => true                     # 時刻をisodateに
      retry_delay => 10                   # 挿入失敗時のリトライ数
      uri => "mongodb://192.168.x.x"      # mongodb接続文字列
      workers => 1                        # outputで使われるコア数(並列度)
    }
}

としてみた。この結果mongodbに入った情報は、以下の通り。
{
    "_id" : ObjectId("56882fc7564ba8d0b3000002"),
    "message" : "2015/11/21 00:00:28\tserver1\tobject1\tmetric1\t0.13\t2015\t11\t21\t00\t00\t05\r",
    "@version" : "1",
    "@timestamp" : ISODate("2015-11-20T15:00:05.000+0000"),
    "host" : "WIN-O4KS6DHF31D",
    "path" : "C:\\test\\test.csv",
    "time" : ISODate("2015-11-20T15:00:28.000+0000"),
    "hostname" : "server1",
    "object" : "object1",
    "metric" : "metric1",
    "value" : 0.13,
    "data1" : "2015",
    "column7" : "11",
    "column8" : "21",
    "column9" : "00",
    "column10" : "00",
    "column11" : "05"
}
随分と想定外のデータが入ってしまっている。logstash内部やelasticsearchで使うフィールドが
含まれているみたい。mutateのremove_fieldを使用して削除すればいいのかなと。
filterセクションのmutate pluginで以下を追加してみる。
    remove => "message"
    remove => "@version"
    remove => "@timestamp"
    remove => "host"
    remove => "path"
    remove => "column7"
    remove => "column8"
    remove => "column9"
    remove => "column10"
    remove => "column11"
これをすると、以下のエラーがでる
NoMethodError: undefined method `to_iso8601' for nil:NilClass
調べると、もともと@timestampは必須の項目のようで、mongodb pluginのソースをみても、
@timestamp前提で実装されている部分がある。ちなみに、@timestampを削除外にして進めると、エラーがなくなり、登録データもかなり近い状態となった。
{
    "_id" : ObjectId("568846b0564ba8b65b000001"),
    "@timestamp" : ISODate("2016-01-02T21:52:48.431+0000"),
    "time" : ISODate("2015-11-20T15:00:35.000+0000"),
    "hostname" : "server1",
    "object" : "object1",
    "metric" : "metric1",
    "value" : 0.13,
    "data1" : "2015"
}
やはり@timestampが不要(データサイズがかさむ)。ということで、mongodb pluginのソースを
少々いじり、mongodbに登録時のみ@timestampを削除するように1行追加してみた。
C:\logstash-2.1.1\vendor\bundle\jruby\1.9\gems\logstash-output-mongodb-2.0.3\lib\logstash\outputs\mongodb.rbの56行目(insert_oneの直前)に以下を追加
document.delete("@timestamp")
これで登録すると、無事想定通りのデータができあがった。
あとはこのpluginを別のpluginとして登録するようにすれば、とりあえずは解決できそう。
もっとスマートな方法があるかと思うが、とりあえず、終了。

備忘録)
 input pluginのfileだが、Windows環境ではワイルドカードを使うことができません。どうもjruby
 環境にbugがあるようです。rubyだと出ないという記事もありました。