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の場合はコレ使えば直接流し込めるのかな?