怠惰系エンジニアのメモ帳

勉強した内容をメモしていきます。解説ブログではないので悪しからず。

Log4j2からElasticsearchにログを流し込む

ログをファイルに出力するのではなく、Elasticsearchに流し込む方法が知りたかったので調べてみました。
「 Spring(SpringBoot)アプリケーションから出力されるログをElasticsearchに流し込む」のがゴールになります。
ログ実装には Log4j2 を用います。(Logbackでもいいのですが、お仕事では Log4j2 が採用されているので。。。)

この方法が正しいわけではないと思うので、ご指摘等いただけると幸いです。

結論

データ収集用のミドルウェア Logstash を経由することで Elasticsearch にログを流し込めました。

www.elastic.co www.elastic.co

なお、ログ可視化のために Kibana を使いました。

www.elastic.co

環境

今回 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.4
    • Logstash : docker.elastic.co/logstash/logstash:6.2.2
    • Kibana : docker.elastic.co/kibana/kibana:6.2.4
  • Spring Boot 1.5.12
    • Log4j2は依存関係に spring-boot-starter-log4j2 を追加して使用。
    • なお、log4j2 を使用する場合 spring-boot-starter-logging を依存関係から除外してください。

準備

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>

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 を立ち上げておくと、各コンテナの状態が分かりやすいのでオススメです。

Kibanalocalhost:5601) にアクセスして、以下のような画面が表示されれば準備OKです。

f:id:tk5_21:20180421235025p:plain

大丈夫だとは思いますが、念のため、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 を確認してみましょう。

f:id:tk5_21:20180422000730p:plain

Elasticsearch にログが転送されていれば、上記のような画面が表示されます。
「index pattern」には logstash.conf で指定したindexと同じパターンになるような文字列(今回は logstash-2018.04.21)を入力し、「Next step」を押下します。

f:id:tk5_21:20180422000735p:plain

「Time Filter field name」は @timestamp でいいです。 「Create index pattern」を押下後、サイドメニューの「Discover」をクリックします。

f:id:tk5_21:20180422000744p:plain

SpringBootの起動ログが表示されていればOKです。 Elasticsearch にログを流し込めてます。

まとめ

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