logstash を使って手元にあるファイルを elasticsearch に取り込む

手元にあるファイルをログサーバーとかを通さずに elasticsearch に取り込みたくなりました。fluentd だと、不特定多数のログをバッチ的に処理するのは不向きな気がしたので、ただのコマンドラインツールとして使える logstash を使ってみました。


あまり紹介記事も見ないので、logstash の簡単な紹介もしてみます。とはいえ触り始めてから2日くらいしかたってないので、いろいろ間違ってるかもしれません。

## logstash とは

logstash のトップページにはこんな風に書いてあります。

http://logstash.net/
> logstash is a tool for managing events and logs. You can use it to collect logs, parse them, and store them for later use (like, for searching). Speaking of searching, logstash comes with a web interface for searching and drilling into all of your logs.

ようするに、ログを集めて、パースして、保存する為の何かです。web interface と言っているのは logstash が組み込みで持っている elasticsearch と kibana の事のようです。

### アーキテクチャ

だいたいこんな感じです。ログを Input Plugin で受けとって、Filter で処理してから Output Plugin でどこかに出力します。普通ですね。

~~~~
Any Where -[Input]-> Input Plugin -[Event]-> Filters -[Event]-> Output Plugin -[Output]-> Any Where
~~~~

Input Plugin, Output Plugin には Codec を指定できるものがあって、(stdin や stdout など) その場合は Event と入出力の変換に Codec が使われます。Codec を指定できないものは Plugin 自体が入力を Event に変換をすることになっています。

Event はログの1レコードを表しいるオブジェクトで、連想配列して使えるデータ型です。生の入力は大体の場合 `message` というキーに入ってるようです。


紹介記事などで良く見る redis と組み合わせた shipper, broker, indexer の構成は使い方の一つでしかないと思っています。


### 動かしてみる

http://logstash.net/docs/1.4.2/tutorials/getting-started-with-logstash をの通りに進めれば使えるようになるんですが、それだけだとさみしいので簡単な例を。


`logstash` コマンドは設定がないと動きません。設定は `-e` か `-f` で指定します。

- `-e`: 設定を直接指定
- `-f`: 設定ファイルを指定


標準入力から読みこんで、rubydebug codec で出力させてみます。

~~~~ console
$ echo -e 'logstash\nfluentd\nflume' | bin/logstash -e 'input { stdin {} } output { stdout {codec => rubydebug } }'
{
       "message" => "logstash",
      "@version" => "1",
    "@timestamp" => "2015-01-17T16:18:46.175Z",
          "host" => "hope"
}
{
       "message" => "fluentd",
      "@version" => "1",
    "@timestamp" => "2015-01-17T16:18:46.175Z",
          "host" => "hope"
}
{
       "message" => "flume",
      "@version" => "1",
    "@timestamp" => "2015-01-17T16:18:46.175Z",
          "host" => "hope"
}
~~~~


### 設定ファイル

ruby の DSL に近いです。詳細は http://logstash.net/docs/1.4.2/configuration を参照してください。

~~~~ruby
input {
  stdin {}
}

filter {
  mutate {
    replace => {message => "%{message} こんにちは！"}
  }
}

output {
  stdout {
    codec => rubydebug
  }
}
~~~~


### プラグインとフィルタ

fluentd のように、プラグインとフィルタで色々な入出力やデータフォーマットを扱うことができます。どんなものがあるかは http://logstash.net/docs/1.4.2/ を参照してください。


以下に使えそうなフィルタを少したけ列挙してみます。

- kv: キーバリューな行を展開
- json: そのまま
- replace: フィールドを編集したり型を変えたり
- grok: 非定型なログを処理する
- date: 日付をパースして日付型にする


## ltsv なログファイルをelasticsearchに取り込む

これがやりたくて調べたのでした。http://ltsv.org/ にある "Labels for Web server's Log" に従った ltsv のログを処理してみます。

設定ファイルをこんな感じで作っておきます。

logstash.conf:

~~~~ruby
  input {
    stdin {}
  }

  filter {
    kv {
      field_split => "\t"
      value_split => ":"
    }
    date {
      match => [time, "'['dd/MMM/YYYY:HH:mm:ss Z']'"]
      locale => us
    }
    useragent {
      source => ua
      prefix => "ua."
    }
    mutate {
      convert => {
        status => integer
        reqtime => integer
        size => integer
      }
    } 
  }

  output {
    elasticsearch {
      host => localhost
      protocol => http
    }
  }
~~~~


簡単な解説と注意点を。

- kv filter で ltsv をフィールドに分割します。
- date filter で日付をタイムスタンプフィールドに保存します。このとき locale に us を指定しないと月のパースに失敗してしまいます。
- mutate filter で一部のフィールドを数値型に変更しておきます。
- elasticsearch output で elasticsearch に登録します。デフォルトでは elasticsearch のクラスタに参加して登録するようなので、クラスタ名を変更している場合は以下のどちらかをしておくとよさそうです。
  - protocol を http にする
  - cluster 属性にクラスタ名を指定する


あとは logstash を実行するだけです。

~~~~console
$ cat /path/to/accesslog | bin/logstash -f logstash.conf
~~~~


## さいごに

logstash を簡単に紹介してみました。あまり流行ってないですが、logstash は簡単に使うことができるし依存も少ないので、ログ処理用のツールとして検討してみるのもいいんじゃないでしょうか。使ってみるとなかなか悪くないです。あと関係ないけど Kibana4 かっこいいです。