Logstash入門

# Logstashとは

[Elastic社](https://www.elastic.co/)が提供するオープンソースのデータ収集エンジン。
リアルタイムのパイプライン処理で異なる種類のデータを統一的なフォーマットへ変換して任意の転送先へ送ることができる。
用途としては、下流の分析処理やビジュアライズ処理に渡すためにデータをクレンジンしたり民主化したりするのに使われる。

![](https://www.elastic.co/guide/en/logstash/current/static/images/logstash.png)

Logstashのパイプラインは`input`（必須）と`output`（必須）、そして`filter`（任意）の３つの要素で構成される。
`input`でデータソースのデータを消費し、それを`filter`で加工し、`output`で転送先へ出力するという流れ。

![](https://www.elastic.co/guide/en/logstash/current/static/images/basic_logstash_pipeline.png)

# Dockerでの起動

まずはお試しで起動してみる。

[officialイメージは非推奨らしい](https://hub.docker.com/_/logstash/)ので、Elastic社のリポジトリからDockerイメージを`pull`する。

[Elastic社のサイト](https://www.elastic.co/guide/en/logstash/current/docker.html)にはバージョン`5.6.1`のコマンドが載っているが、`Error: image logstash/logstash:5.6.1 not found`のエラーが出たので、`5.6.0`にしてみたらできた。

```
$ docker pull docker.elastic.co/logstash/logstash:5.6.0
```

コンテナを起動する。

```
$ docker run --rm -it docker.elastic.co/logstash/logstash:5.6.0
```

エラーになった。
そもそも起動していないElasticSearchへのヘルスチェックで失敗しているっぽい？

```
[2017-09-16T12:53:21,180][INFO ][logstash.outputs.elasticsearch] Elasticsearch pool URLs updated {:changes=>{:removed=>[], :added=>[http://logstash_system:xxxxxx@elasticsearch:9200/]}}
[2017-09-16T12:53:21,182][INFO ][logstash.outputs.elasticsearch] Running health check to see if an Elasticsearch connection is working {:healthcheck_url=>http://logstash_system:xxxxxx@elasticsearch:9200/, :path=>"/"}
[2017-09-16T12:53:21,390][WARN ][logstash.outputs.elasticsearch] Attempted to resurrect connection to dead ES instance, but got an error. {:url=>"http://logstash_system:xxxxxx@elasticsearch:9200/", :error_type=>LogStash::Outputs::ElasticSearch::HttpClient::Pool::HostUnreachableError, :error=>"Elasticsearch Unreachable: [http://logstash_system:xxxxxx@elasticsearch:9200/][Manticore::ResolutionFailure] elasticsearch: Name or service not known"}
[2017-09-16T12:53:21,391][INFO ][logstash.outputs.elasticsearch] New Elasticsearch output {:class=>"LogStash::Outputs::ElasticSearch", :hosts=>["http://elasticsearch:9200"]}
```

これは、コンテナに環境変数`XPACK_MONITORING_ENABLED=false`を定義すれば解決する。

```
$ sudo docker run --rm -it -e XPACK_MONITORING_ENABLED=false docker.elastic.co/logstash/logstash:5.6.0
2017/09/16 12:56:01 Setting 'xpack.monitoring.enabled' from environment.
Sending Logstash's logs to /usr/share/logstash/logs which is now configured via log4j2.properties
[2017-09-16T12:56:11,121][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"fb_apache", :directory=>"/usr/share/logstash/modules/fb_apache/configuration"}
[2017-09-16T12:56:11,125][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"netflow", :directory=>"/usr/share/logstash/modules/netflow/configuration"}
[2017-09-16T12:56:11,142][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"arcsight", :directory=>"/usr/share/logstash/vendor/bundle/jruby/1.9/gems/x-pack-5.6.0-java/modules/arcsight/configuration"}
[2017-09-16T12:56:11,148][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.queue", :path=>"/usr/share/logstash/data/queue"}
[2017-09-16T12:56:11,149][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.dead_letter_queue", :path=>"/usr/share/logstash/data/dead_letter_queue"}
[2017-09-16T12:56:11,189][INFO ][logstash.agent           ] No persistent UUID file found. Generating new UUID {:uuid=>"262028fc-f463-4f67-9cad-66056c1b993c", :path=>"/usr/share/logstash/data/uuid"}
[2017-09-16T12:56:11,528][INFO ][logstash.pipeline        ] Starting pipeline {"id"=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>500}
[2017-09-16T12:56:11,979][INFO ][logstash.inputs.beats    ] Beats inputs: Starting input listener {:address=>"0.0.0.0:5044"}
[2017-09-16T12:56:12,014][INFO ][logstash.pipeline        ] Pipeline main started
[2017-09-16T12:56:12,022][INFO ][org.logstash.beats.Server] Starting server on port: 5044
[2017-09-16T12:56:12,085][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9600}
```

動作確認として、`~/pipeline`というディレクトリを作り、その中に`simple.conf`というファイル名で↓の内容を保存する。（ファイル名は何でもいい）

```
input {
	stdin {}
}

output {
	stdout {}
}
```

これはパイプラインの定義ファイルで、今は標準出力から入力を受け付け、それを標準出力へと出力するという定義になっている。

Dockerで起動する際、パイプライン処理の定義ファイルはデフォルトではコンテナ内の`/usr/share/logstash/pipeline/`配下のファイルを参照する。
今は`~/pipeline/`配下にファイルを作成したので、コンテナの`/usr/share/logstash/pipeline/`にマウントするようにしている。

↓のようにコンテナを起動できる。

```
$ sudo docker run --rm -it -v ~/pipeline/:/usr/share/logstash/pipeline/ -e XPACK_MONITORING_ENABLED=false docker.elastic.co/logstash/logstash:5.6.0
2017/09/16 13:30:45 Setting 'xpack.monitoring.enabled' from environment.
Sending Logstash's logs to /usr/share/logstash/logs which is now configured via log4j2.properties
[2017-09-16T13:30:55,762][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"fb_apache", :directory=>"/usr/share/logstash/modules/fb_apache/configuration"}
[2017-09-16T13:30:55,765][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"netflow", :directory=>"/usr/share/logstash/modules/netflow/configuration"}
[2017-09-16T13:30:55,780][INFO ][logstash.modules.scaffold] Initializing module {:module_name=>"arcsight", :directory=>"/usr/share/logstash/vendor/bundle/jruby/1.9/gems/x-pack-5.6.0-java/modules/arcsight/configuration"}
[2017-09-16T13:30:55,791][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.queue", :path=>"/usr/share/logstash/data/queue"}
[2017-09-16T13:30:55,792][INFO ][logstash.setting.writabledirectory] Creating directory {:setting=>"path.dead_letter_queue", :path=>"/usr/share/logstash/data/dead_letter_queue"}
[2017-09-16T13:30:55,823][INFO ][logstash.agent           ] No persistent UUID file found. Generating new UUID {:uuid=>"1bded84b-c671-42d3-b076-9b6d7f87d3c5", :path=>"/usr/share/logstash/data/uuid"}
[2017-09-16T13:30:56,004][INFO ][logstash.pipeline        ] Starting pipeline {"id"=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>500}
[2017-09-16T13:30:56,031][INFO ][logstash.pipeline        ] Pipeline main started
The stdin plugin is now waiting for input:
[2017-09-16T13:30:56,096][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9600}

```

今は標準入力からの入力待ち状態なので、適当に`hello`と入力してみると、標準出力にタイムスタンプ付きで`hello`と出力されることが確認できる。

```
[2017-09-16T13:30:56,031][INFO ][logstash.pipeline        ] Pipeline main started
The stdin plugin is now waiting for input:
[2017-09-16T13:30:56,096][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9600}

hello
2017-09-16T13:31:13.290Z 5df0006be502 hello
```

# パイプライン定義ファイル（`Pipeline Configuration Files`）

パイプライン処理に使用するプラグインやそれらの設定を記述することで、パイプラインを定義する。

ファイル構造の詳細は[こちら](https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html)を参照。

Logstash起動時に`-f`オプションで使用するパイプライン定義ファイルを指定できる。

```
$ bin/logstash -f logstash-simple.conf
```

`-e`オプションでコマンドラインで直接パイプラインを定義することもできる。

```
$ bin/logstash -e 'input { stdin { } } output { stdout {} }'
```

特に指定がない場合は`/etc/logstash/conf.d`配下の全ファイルを参照するようなので、
無関係なファイルやバックアップ等は配置しないようにした方がいい。

また、LogstashをDockerで起動する場合、デフォルトではコンテナ内の`/usr/share/logstash/pipeline/`配下のファイルを参照する。
なので、例えば`~/pipeline/`配下に使用したいパイプライン定義ファイルがある場合、`-v`オプションでコンテナの`/usr/share/logstash/pipeline/`にマウントすれば使用できる。

ちなみに、コンテナ内の`/usr/share/logstash/pipeline/`にはデフォルトで`logstash.conf`があるらしい。

```
$ sudo docker run --rm -it docker.elastic.co/logstash/logstash:5.6.0 cat /usr/share/logstash/pipeline/logstash.conf
input {
  beats {
    port => 5044
  }
}

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

## input

`input`はLogstashにデータを取り込むために利用する。
よく利用されるものとして例えば↓のようなものがある。

| プラグイン | 説明 |
|---------|-----|
| file | `tail -0F`に似た挙動でファイルを読み込む。 |
| syslog | `514`番ポート`RFC3164`形式のログを受け付ける。 |

詳細な情報は[こちら](https://www.elastic.co/guide/en/logstash/current/input-plugins.html)を参照。

## filter

| プラグイン | 説明 |
|---------|-----|
| mutate | イベントのフィールドに対してリネーム、削除、置換、修正等の変換処理を行う。 |
| drop | イベントを削除する。（例えば不要なデバッグログを削除するなどの使い方） |
| clone | イベントのコピーを作成する。フィールドの追加や削除が可能。 |

詳細な情報は[こちら](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html)を参照。

## output

１つのイベントは複数の`output`を通ることができる。
すべての`output`が呼ばれたとき、イベントの処理が完了する。

| プラグイン | 説明 |
|---------|-----|
| file | ディスク上のファイルに出力する。 |
| elasticsearch | ElasticSearchに転送する。 |

詳細な情報は[こちら](https://www.elastic.co/guide/en/logstash/current/output-plugins.html)を参照。

## codec

`codec`は`input`または`output`の一部として機能する。

| プラグイン | 説明 |
|---------|-----|
| json | JSON形式を扱う。 |
| multiline | 複数行のテキスト（例えばJavaのスタックトレースとか）を扱う。 |

詳細な情報は[こちら](https://www.elastic.co/guide/en/logstash/current/codec-plugins.html)を参照。

# 設定ファイル （`Setting Files`）

後で書く。

# 参考

* [リファレンス](https://www.elastic.co/guide/en/logstash/current/index.html)
    * [pipeline設定ファイル記述例](https://www.elastic.co/guide/en/logstash/current/config-examples.html)
    * [LogstashをDockerで動かす方法](https://www.elastic.co/guide/en/logstash/current/docker.html)
* [ElasticSearchへのヘルスチェックでLogstashの起動に失敗する場合の対処](https://github.com/docker-library/logstash/issues/85)