Log4j2からElasticsearchにログを流し込む
ログをファイルに出力するのではなく、Elasticsearch
に流し込む方法が知りたかったので調べてみました。
「 Spring(SpringBoot)アプリケーションから出力されるログをElasticsearch
に流し込む」のがゴールになります。
ログ実装には Log4j2
を用います。(Logback
でもいいのですが、お仕事では Log4j2
が採用されているので。。。)
この方法が正しいわけではないと思うので、ご指摘等いただけると幸いです。
結論
データ収集用のミドルウェア Logstash
を経由することで Elasticsearch
にログを流し込めました。
なお、ログ可視化のために Kibana
を使いました。
環境
今回 Elasticsearch
, Logstash
, Kibana
の環境(この3つで ELK Stack
と呼ばれてるっぽい)はDockerを利用して構築しています。
- Docker for Mac(version 18.03.0-ce, build 0520e24)
Elasticsearch
: docker.elastic.co/elasticsearch/elasticsearch:6.2.4Logstash
: docker.elastic.co/logstash/logstash:6.2.2Kibana
: docker.elastic.co/kibana/kibana:6.2.4
- Spring Boot 1.5.12
- Log4j2は依存関係に
spring-boot-starter-log4j2
を追加して使用。 - なお、log4j2 を使用する場合
spring-boot-starter-logging
を依存関係から除外してください。
- Log4j2は依存関係に
準備
1. ELK StackをDockerで用意する
docker-compose.yml
と、各種設定ファイルを用意する。(全体的なフォルダ構成は最後に記載)
docker-compose.yml
version: '2' services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4 container_name: elasticsearch ports: - "9200:9200" - "9300:9300" environment: - discovery.type=single-node logstash: image: docker.elastic.co/logstash/logstash:6.2.2 container_name: logstash ports: - "5044:5044" volumes: - ./logstash/config/:/usr/share/logstash/config/ - ./logstash/pipeline/:/usr/share/logstash/pipeline/ links: - elasticsearch kibana: image: docker.elastic.co/kibana/kibana:6.2.4 container_name: kibana ports: - "5601:5601" volumes: - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml links: - elasticsearch
- イメージはDockerHubではなく、Elastic社から取得しています。
- ※なんかDockerHubのは非推奨らしい
elasticsearch.yml
用意はしているんですが、ボリュームをマウントしてないので意味ないですね。 参考程度に。
network.host: 0.0.0.0 cluster.name: elasticsearch discovery.type: single-node
logstash.yml
http.host: "0.0.0.0" path.config: /usr/share/logstash/pipeline xpack.monitoring.elasticsearch.url: http://elasticsearch:9200 xpack.monitoring.elasticsearch.username: logstash_system xpack.monitoring.elasticsearch.password: changeme
logstash.conf
input { tcp { mode => "server" host => "0.0.0.0" port => 5044 } } output { elasticsearch { hosts => "elasticsearch:9200" index => "logstash-%{+YYYY.MM.dd}" document_type => "logs" } }
- サーバーモードで入力を受け付け、Elasticsearchに出力します。
2. Log4j2の設定
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="OFF"> <Properties> <Property name="loglayout">[%d{yyyy-MM-dd HH:mm:ss.SSS}],%-5p,%t,%c:%m%n</Property> </Properties> <Appenders> <Console name="CONSOLE" target="SYSTEM_OUT"> <PatternLayout pattern="${loglayout}"/> </Console> <Socket name="LOG_STASH" host="localhost" port="5044" > <JsonLayout compact="true" eventEol="true" /> </Socket> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="CONSOLE" /> <AppenderRef ref="LOG_STASH" /> </Root> </Loggers> </Configuration>
SocketAppender
を使用し、Logstash
にログを転送するよう設定しています。<JsonLayout compact="true" eventEol="true" />
は、1行1レコードとして扱いたい場合に設定するようです。
ELKを立ち上げ、ログを流し込む
docker-compose up
で、ELKを立ち上げます。
$ docker-compose up Creating network "docker_default" with the default driver Creating elasticsearch ... done Creating kibana ... done Creating logstash ... done Attaching to elasticsearch, kibana, logstash ...
起動するまで少し時間がかかるのでしばらく待って、localhost:5601
にアクセスします。
※ Kitematic
を立ち上げておくと、各コンテナの状態が分かりやすいのでオススメです。
Kibana
(localhost:5601
) にアクセスして、以下のような画面が表示されれば準備OKです。
大丈夫だとは思いますが、念のため、docker-compose ps
で全てのコンテナが稼働しているか確認しておいてください。
※もしくは Kitematic
で確認
$ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------------- elasticsearch /usr/local/bin/docker-entr ... Up 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp kibana /bin/bash /usr/local/bin/k ... Up 0.0.0.0:5601->5601/tcp logstash /usr/local/bin/docker-entr ... Up 0.0.0.0:5044->5044/tcp, 9600/tcp
ELKが立ち上がったら、アプリケーションを実行してログを出力します。
SpringBootの起動時、エラーが出ていなければ Logstash
にログが転送されているはずです。
SpringBootが起動できたら Kibana
を確認してみましょう。
Elasticsearch
にログが転送されていれば、上記のような画面が表示されます。
「index pattern」には logstash.conf
で指定したindexと同じパターンになるような文字列(今回は logstash-2018.04.21
)を入力し、「Next step」を押下します。
「Time Filter field name」は @timestamp
でいいです。
「Create index pattern」を押下後、サイドメニューの「Discover」をクリックします。
SpringBootの起動ログが表示されていればOKです。 Elasticsearch にログを流し込めてます。
まとめ
Log4j2
はSocketAppender
を使用して、Logstash
にログを送信する。Logstash
からElasticsearch
にデータ転送できる。
フォルダ構成(一部省略)
./ ├── docker │ ├── docker-compose.yml │ ├── elasticsearch │ │ └── config │ │ └── elasticsearch.yml │ ├── kibana │ │ └── config │ │ └── kibana.yml │ └── logstash │ ├── config │ │ └── logstash.yml │ └── pipeline │ └── logstash.conf ├── pom.xml ├── src └── main ├── java └── resources ├── application.yml └── log4j2.xml
所感
とりあえず、Elasticsearch
にログを流し込む、という目的は達成されましたが
ログをそのまま送信しているので、セキュリティはガバガバ。。。
あと、Elasticsearch
以外に Logstash
とか Kibana
とか知れたのは大きいですね。 (使えるわけではないけど)
余談
ELKのDockerイメージは既にあって、イメージサイズも小さい
これも試したみたんですが、Logstash
にログを転送するにはSSL(TLS)接続が必要だったので一旦諦めました。(ネットワークよく分からん。。。)
この辺詳しい場合は、こちらを使用するほうが楽かも。
Logback用のlogback-elasticsearch-appender
なるものがGitHubにある
Logbackの場合はコレ使えば直接流し込めるのかな?