Mac OS X上にてELKスタック構築及びJAVAによるログをElasticsearchに出力(log4j2)

みなさん、お久しぶりです。
# ELKスタック構築
## 前準備
ELKをインストールする為に、HomebrewとJAVA JDKが必要となります。インストールされていない方は先に入れておいてください。
### Homebrew
自分の作業するパスの下に

```
$ mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
```
### Java SDK
Oracleの**[Java SE Downloads](https://www.oracle.com/technetwork/java/javase/downloads/index.html)**に参考してください。
念のためJDK 8にしました。

## ELK
### ELKとは
ELKスタックとはElasticsearch社のElasticsearch（解析） + Logstash（収集） + Kibana（可視化）の３つの製品の総称です。 
（実際に動く際に、LEKのフローで動いてますが）
### Elasticsearch
Elasticsearch は Elastic 社が開発しているオープンソースの全文検索エンジンです。
大量のドキュメントから目的の単語を含むドキュメントを高速に抽出することができます。

Elasticsearch はリレーショナルデータベースではないため、SQL文 は使用できません。
代わりに RESTful インターフェースを使って操作します。

今回はElasticsearch　6.2.4を使用します。
#### インストール
```
$ brew install elasticsearch
```
#### ホストを設定する
まずは、`elasticsearch.yml`を見つかります。

```
$ brew info elasticssearch
```
でこのような情報が出てくると思います。

```
...(Blah Blah Blah)...
Data:    /usr/local/var/lib/elasticsearch/elasticsearch_JP23417/
Logs:    /usr/local/var/log/elasticsearch/elasticsearch_JP23417.log
Plugins: /usr/local/var/elasticsearch/plugins/
Config:  /usr/local/etc/elasticsearch/
...(Blah Blah Blah)...
```
`elasticsearch.yml`は、`Config`に書いてあるパスの下にあります。
それを開いて、`network.host`を実際に使うIPアドレスに変更してください。今回はローカル環境に構築するので、コメントを外してこう設定しました。

```
network.host: localhost
```
#### 動作確認
`brew services elasticsearch start`でElasticsearchを起動する。
Elasticsearchはデフォルトで9200番ポートで動いていますので、http://localhost:9200 にアクセスすると、このような情報が表示されます。

```
{
  "name" : "ry1EXQC",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "ZMYVLV-eR-G5hBrQ6QmSGA",
  "version" : {
    "number" : "6.2.4",
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
```

### Logstash
Logstashは、オープンソースのサーバーサイドデータ処理パイプラインです。膨大な数のソースから同時にデータを取り込み、変換して、お好みの格納庫（スタッシュ）に送信します。お勧めのスタッシュは、もちろんElasticsearchです。

今回はLogstash　6.2.4を使用します。
#### インストールと起動
```
$ brew install logstash
$ brew services start logstash
```
Logstashは実はコンフィグに連動して動いてます。各シーンに違うコンフィグを配置する必要があります。とりあえずこれでKibanaを動けるはずなので、詳しくはあとで説明します。

### Kibana
KibanaはElasticsearchのデータを簡単に可視化するツールです。

今回はKibana　6.2.4を使用します。

#### インストール
```
$ brew install kibana
```

#### ポートとElasticsearchを設定する
まずは、`kibana.yml`を見つかります。

```
$ brew info kibana
```
でこのような情報が出てくると思います。

```
...(Blah Blah Blah)...
Config: /usr/local/etc/kibana/
...(Blah Blah Blah)...
```
`kibana.yml`は、`Config`に書いてあるパスの下にあります。
それを開いて、`server.port`と`elasticsearch.url`を実際に使うものに変更してください。今回はデフォルトの設定のままでこう設定しました。

```
...(Blah Blah Blah)...
server.port: 5601 

...(Blah Blah Blah)...

elasticsearch.url: "http://localhost:9200”
...(Blah Blah Blah)...
```
#### 確認
これできたら、http://localhost:5601/status から確認できるはずです。
このような画面出てきます。
<img width="1440" alt="スクリーンショット 2018-09-12 16.56.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/169507/63243b7a-6a12-a187-efa8-c3a88c521ab8.png">

# JAVAによるログ出力(log4j2)
今回はTCPによって、ログをElasticsearchに送信するツールを作ります。
## Mavenプロジェクトを作成
どっかのIDEでMavenプロジェクトを自動生成するのがあると思いますが、ぜひそれを使ってください。
だいたいこういう形で生成すれば問題ないです。ご参考まで。
<img width="358" alt="スクリーンショット 2018-09-12 17.07.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/169507/b4f2dd44-8e0d-9a13-b5bc-4304368e79fd.png">
今回のパッケージ名はlog4j2.localです（実はなんでもいいです）。
### Mavenのライブラリ配置
つまり`pom.xml`の中身ってことですね。
`dependencies`タグに以下のように追加してください。

```pom.xml
<dependencies>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
</dependencies>
```
### Log4j2の配置
つまり`log4j2.xml`の中身のことです。Log4j2はこれに従って、ログの送信先を決まります。
今回はもちろんLogstash経由でElasticsearchに送信しますが、Debugしやすさも考慮すると一応Consoleにも出力する形にしておきました。

```log4j2.xml
<configuration status="OFF">
    <appenders>
        <Socket name="Logstash" host="localhost" port="9601" protocol="TCP">
            <PatternLayout pattern="%d|%t|%p|%c|%L|%m%n" />
        </Socket>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d|%t|%p|%c|%L|%m%n" />
        </Console>
    </appenders>
    <loggers>
        <root level="all">
            <AppenderRef ref="Logstash"/>
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>
```
個性化したい方は**[このページ](https://qiita.com/pica/items/f801c74848f748f76b58)**に参考してください。

### Mainクラス
ログを出力する挙動です。

```Main.java
package log4j2.local;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;


public class Main {
    private static Logger logger = LogManager.getLogger("test");

    public static void main(String[] args) {
        logger.error("エラーメッセージです");
    }
}
```
これを実行すると、Consoleにはこのようなログが出てきます。
（Logstashにはまだ繋いでないので、もちろんElasticsearchにも保存されません。）

```
2018-09-12 12:55:13,962|main|ERROR|test|13|エラーメッセージです
```
## Logstashを配置
### Logstashコンフィグ
好きなパスで大丈夫で、logstash-tcp.confを作りましょう。（tcp通信なのでこの名前にしただけです。）
Logstashはデフォルトで`9600~9700`のポート全部使えるので、今回は9601番ポートを使います。（必ず`log4j2.xml`の`<Socket>`タグと**同じポート**にしてください。）

```logstash-tcp.conf
input {
    tcp {
        host => "localhost"
        port => "9601"
        mode => "server"
        type => "eslocallogger"
    }
}

filter {
    mutate{
        split => ["message","|"]
        add_field =>   {
            "Datetime" => "%{[message][0]}"
        }
        add_field =>   {
            "Classname" => "%{[message][1]}"
        }
        add_field =>   {
            "Level" => "%{[message][2]}"
        }
        add_field =>   {
            "Logger" => "%{[message][3]}"
        }
        add_field =>   {
            "Message" => "%{[message][5]}"
        }
    }
}
output {
    stdout {
        codec => rubydebug
    }
    elasticsearch {
        hosts => "localhost:9200"
    }
}
```
ここではSchemaを分けるためにFilterを使いましたが、使わなくてもデフォルトのカラムは自動的にパースされます。
（ここでは、Logstashに入ってきたエラーメッセージを`|`で区きりします。）
### Logstashをコンフィグに連結して再起動
```
$ brew services stop logstash
$ logstash -f ./logstash-tcp.conf --experimental-java-execution
```
`--experimental-java-execution`のフラグがあると、JAVAのエンジンで走ります。
詳しくは**[Meet the New Logstash Java Execution Engine](https://www.elastic.co/blog/meet-the-new-logstash-java-execution-engine)**からご覧ください。確かそうした方がスループットが大分上がります。
## 実行してみよう
### Console
```
2018-09-12 18:05:39,737|main|ERROR|test|13|エラーメッセージです
```
### Logstash Console
```
[2018-09-12T18:05:40,464][DEBUG][logstash.pipeline        ] Pushing flush onto pipeline {:pipeline_id=>"main", :thread=>"#<Thread:0x5caa3237 sleep>"}
{
         "Level" => "ERROR",
    "@timestamp" => 2018-09-12T09:05:39.847Z,
        "Logger" => "test",
          "port" => 60614,
       "message" => [
        [0] "2018-09-12 18:05:39,737",
        [1] "main",
        [2] "ERROR",
        [3] "test",
        [4] "13",
        [5] "エラーメッセージです"
    ],
          "type" => "eslocallogger",
       "Message" => "エラーメッセージです",
      "Datetime" => "2018-09-12 18:05:39,737",
          "host" => "localhost",
      "@version" => "1",
     "Classname" => "main"
}
```
### Kibana
Kibanaの**Management**画面に行ってリロードすると、このような画面が出てくるはずです。
<img width="1440" alt="スクリーンショット 2018-09-12 18.08.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/169507/ce812a21-d5dd-e800-3a6a-efe9eef58190.png">
`Next step`に行って、`filter`を`@timestamp`にして`Create index pattern`をクリックすると、インデックスの可視化を始めます。
<img width="1458" alt="スクリーンショット 2018-09-12 18.11.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/169507/dbedc73b-efae-36af-85f2-f1d8b1096acd.png">
`Discover`画面に入ったら、時間軸のデータを見れます。
<img width="1458" alt="スクリーンショット 2018-09-12 18.11.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/169507/6b93f756-bd1c-8626-7e9d-a16f1d6bc7f1.png">
詳しくは**[Kibanaの使い方](https://qiita.com/namutaka/items/b67290e75cbd74cd9a2f)**に参考してください。

# 参考元
[Installing the ELK Stack on Mac OS X](https://logz.io/blog/elk-mac/)
[ElasticSearch+Logstash+Kibana+log4j2 官方6.1.1版安装配置简介](https://blog.csdn.net/z369702770/article/details/78930541)
[LogStash的Filter的使用](https://www.cnblogs.com/qq27271609/p/4762562.html)
[Elastic Stack](https://www.elastic.co/jp/products)